Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110539218
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
132 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml b/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml
index 473901f14b..63f54688f5 100644
--- a/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml
+++ b/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml
@@ -1,2141 +1,3724 @@
<!--
The FreeBSD Documentation Project
- $FreeBSD: doc/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml,v 1.15 1999/12/30 22:06:51 nik Exp $
+ $FreeBSD: doc/en_US.ISO_8859-1/books/handbook/internals/chapter.sgml,v 1.16 2000/01/14 11:04:56 nbm Exp $
-->
<chapter id="internals">
<title>FreeBSD Internals</title>
<sect1 id="booting">
<title>The FreeBSD Booting Process</title>
<sect2 id="boot-intro">
<title>Introduction</title>
<para><firstterm>Bootstrapping</firstterm> is the process
whereby a computer probes and initializes its devices, and
works out what programs it is supposed to run.</para>
<para>This involves the use of special Read Only Memory chips,
which determine what further operations to do, and these
usually pass control to other chips that do consistency and
memory tests, configure devices, and provide a mechanism for
programs to determine what configuration details were
determined.</para>
<para>In standard personal computers, this involves the BIOS,
which oversees the bootstrap, and CMOS, which stores
configuration; and these understand disks, and they also
understand where on the disk to find a program that will know
how to load up an operating system.</para>
<para>This chapter will not deal with this first part of the
bootstrap process, and focuses on what happens after control
is passed to the program on the disk.</para>
</sect2>
<sect2 id="boot-overview">
<title>Overview of the boot process</title>
<para>FreeBSD uses a three-stage bootstrap by default, which
basically entails three programs which basically call each
other in order (the two <link linkend="boot-blocks">boot
blocks</link>, and the <link
linkend="boot-loader">loader</link>), and which build on the
previous programs understanding and provide increasing amounts
of sophistication.</para>
<para>The kernel is then started, during which devices are
probed for and initialized for use. Once the kernel boot
process is finished, it passes control to the user process
init, which then makes sure the disks are in a usable state,
and then starts the user-level resource configuration which
then mounts filesystems, sets up network cards to act on the
network, and generally starts all the processes that usually
are run on a FreeBSD system at startup.</para>
</sect2>
<sect2 id="boot-blocks">
<title>The boot blocks: Bootstrap stages 1 and 2</title>
<para>The boot blocks are responsible for finding (usually) the
loader, and running it, and thus need to understand how to
find that program on the filesystem, how to run the program,
and also allow minor configuration of how they work.</para>
<sect3 id="boot-boot0">
<title>boot0</title>
<para>There is actually a preceding bootblock, named boot0,
which lives on the <firstterm>Master Boot
Record</firstterm>, the special part of the disk that the
system bootstrap looks for and runs, and it simply shows a
list of possible slices to boot from.</para>
<para>boot0 is very simple, since the program in the
<abbrev>MBR</abbrev> can only be 512 bytes large.</para>
<para>It displays something like this:</para>
<example id="boot-boot0-example">
<title>boot0 screenshot</title>
<screen>
F1 DOS
F2 FreeBSD
F3 Linux
F4 ??
F5 Drive 1
Default: F2</screen>
</example>
</sect3>
<sect3 id="boot-boot1">
<title>boot1</title>
<para>boot1 is found on the boot sector of the boot slice,
which is where <link linkend="boot-boot0">boot0</link>, or
any other program on the <abbrev>MBR</abbrev> expects to
find the program to run to continue the boot process.</para>
<para>boot1 is very simple, since it too can only be 512 bytes
large, and knows just enough about the FreeBSD
<firstterm>disklabel</firstterm>, which stores information
about the slice, to find and execute <link
linkend="boot-boot2">boot2</link>.</para>
</sect3>
<sect3 id="boot-boot2">
<title>boot2</title>
<para>boot2 is slightly more sophisticated, and understands
the FreeBSD filesystem enough to find files on it, and can
provide a simple interface to choose the kernel or loader to
run.</para>
<para>Since the <link linkend="boot-loader">loader</link> is
much more sophisticated, and provides a nice easy-to-use
boot configuration, boot2 usually runs it, but previously it
was tasked to run the kernel directly.</para>
<example id="boot-boot2-example">
<title>boot2 screenshot</title>
<screen>>> FreeBSD/i386 BOOT
Default: 0:wd(0,a)/kernel
boot:</screen>
</example>
</sect3>
</sect2>
<sect2 id="boot-loader">
<title>loader: Bootstrap stage three</title>
<para>The loader is the final stage of the three-stage
bootstrap, and is located on the filesystem, usually as
<filename>/boot/loader</filename>.</para>
<note>
<para>While <filename>/boot/boot0</filename>,
<filename>/boot/boot1</filename>, and
<filename>/boot/boot2</filename> are files there, they are
not the actual copies in the <abbrev>MBR</abbrev>, the boot
sector, or the disklabel respectively.</para>
</note>
<para>The loader is intended as a user-friendly method for
configuration, using an easy-to-use built-in command set,
backed up by a more powerful interpreter, with a more complex
command set.</para>
<sect3 id="boot-loader-flow">
<title>loader program flow</title>
<para>During initialization, the loader will probe for a
console and for disks, and figure out what disk it is
booting from. It will set variables accordingly, and then
the interpreter is started, and the easy-to-use commands are
explained to it.</para>
<para>loader will then read
<filename>/boot/loader.rc</filename>, which by default reads
in <filename>/boot/defaults/loader.conf</filename> which
sets reasonable defaults for variables and reads
<filename>/boot/loader.conf</filename> for local changes to
those variables. <filename>loader.rc</filename> then acts
on these variables, loading whichever modules and kernel are
selected.</para>
<para>Finally, by default, the loader issues a 10 second wait
for keypresses, and boots the kernel if it is interrupted.
If interrupted, the user is presented with a prompt which
understands the easy-to-use command set, where the user may
adjust variables, unload all modules, load modules, and then
finally boot or reboot.</para>
<para>A more technical discussion of the process is available
in &man.loader.8;</para>
</sect3>
<sect3 id="boot-loader-commands">
<title>loader built-in commands</title>
<para>The easy-to-use command set comprises of:</para>
<variablelist>
<varlistentry>
<term>autoboot <replaceable>seconds</replaceable></term>
<listitem>
<para>Proceeds to boot the kernel if not interrupted
within the time span given, in seconds. It displays a
countdown, and the default timespan is 10
seconds.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>boot
<optional><replaceable>-options</replaceable></optional>
<optional><replaceable>kernelname</replaceable></optional></term>
<listitem>
<para>Immediately proceeds to boot the kernel, with the
given options, if any, and with the kernel name given,
if it is.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>help
<optional><replaceable>topic</replaceable></optional></term>
<listitem>
<para>Shows help messages read from
<filename>/boot/loader.help</filename>. If the topic
given is <literal>index</literal>, then the list of
available topics is given.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>include <replaceable>filename</replaceable>
…</term>
<listitem>
<para>Processes the file with the given filename. The
file is read in, and interpreted line by line. An
error immediately stops the include command.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>load <optional><option>-t</option>
<replaceable>type</replaceable></optional>
<replaceable>filename</replaceable></term>
<listitem>
<para>Loads the kernel, kernel module, or file of the
type given, with the filename given. Any arguments
after filename are passed to the file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ls <optional><option>-l</option></optional>
<optional><replaceable>path</replaceable></optional></term>
<listitem>
<para>Displays a listing of files in the given path, or
the root directory, if the path is not specified. If
<option>-l</option> is specified, file sizes will be
shown too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lsdev <optional><option>-v</option></optional></term>
<listitem>
<para>Lists all of the devices from which it may be
possible to load modules. If <option>-v</option> is
specified, more details are printed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>lsmod <optional><option>-v</option></optional></term>
<listitem>
<para>Displays loaded modules. If <option>-v</option> is
specified, more details are shown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>more <replaceable>filename</replaceable></term>
<listitem>
<para>Display the files specified, with a pause at each
<varname>LINES</varname> displayed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>reboot</term>
<listitem>
<para>Immediately reboots the system.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>set <replaceable>variable</replaceable></term>
<term>set
<replaceable>variable</replaceable>=<replaceable>value</replaceable></term>
<listitem>
<para>Set loader's environment variables.</para>
</listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="boot-loader-examples">
<title>loader examples</title>
<para>Here are some practical examples of loader usage.</para>
<itemizedlist>
<listitem>
<para>To simply boot your usual kernel, but in single-user
mode:</para>
<screen><userinput>boot -s</userinput></screen>
</listitem>
<listitem>
<para>To unload your usual kernel and modules, and then
load your old (or another) kernel:</para>
<screen><userinput>unload</userinput>
<userinput>load kernel.old</userinput></screen>
<para>You can use <filename>kernel.GENERIC</filename> to
refer to the generic kernel that comes on the install
disk, or <filename>kernel.old</filename> to refer to
your previously installed kernel (when you've upgraded
or configured your own kernel, for example).</para>
</listitem>
<listitem>
<para>To load a kernel configuration script (an automated
script which does the things you'd normally do in the
kernel boot-time configurator):</para>
<screen><userinput>load -t userconfig_script
<replaceable>/boot/kernel.conf</replaceable></userinput></screen>
</listitem>
</itemizedlist>
</sect3>
</sect2>
<sect2 id="boot-kernel">
<title>Kernel interaction during boot</title>
<para>Once the kernel is loaded by either <link
linkend="boot-loader">loader</link> (as usual) or <link
linkend="boot-boot2">boot2</link> (bypassing the loader), it
examines its boot flags, if any, and adjusts its behaviour as
necessary.</para>
<sect3 id="boot-kernel-bootflags">
<title>Kernel bootflags</title>
<para>Here are the more common boot flags:</para>
<variablelist id="boot-kernel-bootflags-list">
<varlistentry>
<term><option>-a</option></term>
<listitem>
<para>during kernel initialization, ask for the device
to mount as as the root file system.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-C</option></term>
<listitem>
<para>boot from CDROM.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-c</option></term>
<listitem>
<para>run UserConfig, the boot-time kernel
configurator</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-s</option></term>
<listitem>
<para>boot into single-user mode</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<listitem>
<para>be more verbose during kernel startup</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>There are other boot flags, read &man.boot.8; for more
information on them.</para>
</note>
</sect3>
<!-- <sect3 id="boot-kernel-userconfig">
<title>UserConfig: The boot-time kernel configurator</title>
<para> </para>
</sect3> -->
</sect2>
<sect2 id="boot-init">
<title>Init: Process control initialization</title>
<para>Onqe the kernel has finished booting, it passes control to
the usqr process <command>init</command>, which is located at
<filename>/sbin/init</filename>, or the program path specified
in the <envar>init_path</envar> variable in
<command>loader</command>.</para>
<sect3 id="boot-autoreboot">
<title>Automatic reboot sequence</title>
<para>The automatic reboot sequence makes sure that the
filesystems available on the system are consistent. If they
are not, and <command>fsck</command> can not fix the
inconsistencies, <command>init</command> drops the system
into <link linkend="boot-singleuser">single-user mode</link>
for the system administrator to take care of the problems
directly.</para>
</sect3>
<sect3 id="boot-singleuser">
<title>Single-user mode</title>
<para>This mode can be reached through the <link
linkend="boot-autoreboot">automatic reboot
sequence</link>, or by the user booting with the
<option>-s</option> or setting the
<envar>boot_single</envar> variable in
<command>loader</command>.</para>
<para>It can also be reached by calling
<command>shutdown</command> without the reboot
(<option>-r</option>) or halt (<option>-h</option>) options,
from <link linkend="boot-multiuser">multi-user
mode</link>.</para>
<para>If the system console <literal>console</literal> is set
to <literal>insecure</literal> in
<filename>/etc/ttys</filename>, then the system prompts for
the root password before initiating single-user mode.</para>
<example id="boot-insecure-console">
<title>An insecure console in /etc/ttys</title>
<programlisting># name getty type status comments
#
# This entry needed for asking password when init goes to single-user mode
# If you want to be asked for password, change "secure" to "insecure" here
console none unknown off insecure</programlisting>
</example>
<note>
<para>An <literal>insecure</literal> console means that you
consider your physical security to the console to be
insecure, and want to make sure only someone who knows the
root password may use single-user mode, and it does not
mean that you want to run your console insecurely. Thus,
if you want security, choose <literal>insecure</literal>,
not <literal>secure</literal>.</para>
</note>
</sect3>
<sect3 id="boot-multiuser">
<title>Multi-user mode</title>
<para>If <command>init</command> finds your filesystems to be
in order, or once the user has finished in <link
linkend="boot-singleuser">single-user mode</link>, the
system enters multi-user mode, in which it starts the
resource configuration of the system.</para>
<sect4 id="boot-rc">
<title>Resource configuration (rc)</title>
<para>The resource configuration system reads in
configuration defaults from
<filename>/etc/defaults/rc.conf</filename>, and
system-specific details from
<filename>/etc/rc.conf</filename>, and then proceeds to
mount the system filesystems mentioned in
<filename>/etc/fstab</filename>, start up networking
services, starts up miscellaneous system daemons, and
finally runs the startup scripts of locally installed
packages.</para>
<para>&man.rc.8; is a good reference to the resource
configuaration system, as is examining the scripts
themselves.</para>
</sect4>
</sect3>
</sect2>
<sect2 id="boot-shutdown">
<title>Shutdown sequence</title>
<para>Upon controlled shutdown, via <command>shutdown</command>,
<command>init</command> will attempt to run the script
<filename>/etc/rc.shutdown</filename>, and then proceed to send
all processes the terminate signal, and subsequently the kill
signal to any that don't terminate timely.</para>
</sect2>
</sect1>
<sect1 id="memoryuse">
<title>PC Memory Utilization</title>
<para><emphasis>Contributed by &a.joerg;. 16 Apr
1995.</emphasis></para>
<para><emphasis>A short description of how FreeBSD uses memory on the i386
platform</emphasis></para>
<para>The boot sector will be loaded at <literal>0:0x7c00</literal>, and
relocates itself immediately to <literal>0x7c0:0</literal>. (This is
nothing magic, just an adjustment for the <literal>%cs</literal>
selector, done by an <literal>ljmp</literal>.)</para>
<para>It then loads the first 15 sectors at <literal>0x10000</literal>
(segment <makevar>BOOTSEG</makevar> in the biosboot Makefile), and sets
up the stack to work below <literal>0x1fff0</literal>. After this, it
jumps to the entry of boot2 within that code. I.e., it jumps over
itself and the (dummy) partition table, and it is going to adjust the
%cs selector—we are still in 16-bit mode there.</para>
<para>boot2 asks for the boot file, and examines the
<filename>a.out</filename> header. It masks the file entry point
(usually <literal>0xf0100000</literal>) by
<literal>0x00ffffff</literal>, and loads the file there. Hence the
usual load point is 1 MB (<literal>0x00100000</literal>). During load,
the boot code toggles back and forth between real and protected mode, to
use the BIOS in real mode.</para>
<para>The boot code itself uses segment selectors <literal>0x18</literal>
and <literal>0x20</literal> for <literal>%cs</literal> and
<literal>%ds/%es</literal> in protected mode, and
<literal>0x28</literal> to jump back into real mode. The kernel is
finally started with <literal>%cs</literal> <literal>0x08</literal> and
<literal>%ds/%es/%ss</literal> <literal>0x10</literal>, which refer to
dummy descriptors covering the entire address space.</para>
<para>The kernel will be started at its load point. Since it has been
linked for another (high) address, it will have to execute PIC until the
page table and page directory stuff is setup properly, at which point
paging will be enabled and the kernel will finally run at the address
for which it was linked.</para>
<para><emphasis>Contributed by &a.dg;. 16 Apr
1995.</emphasis></para>
<para>The physical pages immediately following the kernel BSS contain
proc0's page directory, page tables, and upages. Some time later when
the VM system is initialized, the physical memory between
<literal>0x1000-0x9ffff</literal> and the physical memory after the
kernel (text+data+bss+proc0 stuff+other misc) is made available in the
form of general VM pages and added to the global free page list.</para>
</sect1>
<sect1 id="dma">
<title>DMA: What it Is and How it Works</title>
<para><emphasis>Copyright © 1995,1997 &a.uhclem;, All Rights
Reserved. 10 December 1996. Last Update 8 October
1997.</emphasis></para>
<para>Direct Memory Access (DMA) is a method of allowing data to be moved
from one location to another in a computer without intervention from the
central processor (CPU).</para>
<para>The way that the DMA function is implemented varies between computer
architectures, so this discussion will limit itself to the
implementation and workings of the DMA subsystem on the IBM Personal
Computer (PC), the IBM PC/AT and all of its successors and
clones.</para>
<para>The PC DMA subsystem is based on the Intel 8237 DMA controller. The
8237 contains four DMA channels that can be programmed independently and
any one of the channels may be active at any moment. These channels are
numbered 0, 1, 2 and 3. Starting with the PC/AT, IBM added a second
8237 chip, and numbered those channels 4, 5, 6 and 7.</para>
<para>The original DMA controller (0, 1, 2 and 3) moves one byte in each
transfer. The second DMA controller (4, 5, 6, and 7) moves 16-bits from
two adjacent memory locations in each transfer, with the first byte
always coming from an even-numbered address. The two controllers are
identical components and the difference in transfer size is caused by
the way the second controller is wired into the system.</para>
<para>The 8237 has two electrical signals for each channel, named DRQ and
-DACK. There are additional signals with the names HRQ (Hold Request),
HLDA (Hold Acknowledge), -EOP (End of Process), and the bus control
signals -MEMR (Memory Read), -MEMW (Memory Write), -IOR (I/O Read), and
-IOW (I/O Write).</para>
<para>The 8237 DMA is known as a “fly-by” DMA controller.
This means that the data being moved from one location to another does
not pass through the DMA chip and is not stored in the DMA chip.
Subsequently, the DMA can only transfer data between an I/O port and a
memory address, but not between two I/O ports or two memory
locations.</para>
<note>
<para>The 8237 does allow two channels to be connected together to allow
memory-to-memory DMA operations in a non-“fly-by” mode,
but nobody in the PC industry uses this scarce resource this way since
it is faster to move data between memory locations using the
CPU.</para>
</note>
<para>In the PC architecture, each DMA channel is normally activated only
when the hardware that uses a given DMA channel requests a transfer by
asserting the DRQ line for that channel.</para>
<sect2>
<title>A Sample DMA transfer</title>
<para>Here is an example of the steps that occur to cause and perform a
DMA transfer. In this example, the floppy disk controller (FDC) has
just read a byte from a diskette and wants the DMA to place it in
memory at location 0x00123456. The process begins by the FDC
asserting the DRQ2 signal (the DRQ line for DMA channel 2) to alert
the DMA controller.</para>
<para>The DMA controller will note that the DRQ2 signal is asserted. The
DMA controller will then make sure that DMA channel 2 has been
programmed and is unmasked (enabled). The DMA controller also makes
sure that none of the other DMA channels are active or want to be
active and have a higher priority. Once these checks are complete,
the DMA asks the CPU to release the bus so that the DMA may use the
bus. The DMA requests the bus by asserting the HRQ signal which goes
to the CPU.</para>
<para>The CPU detects the HRQ signal, and will complete executing the
current instruction. Once the processor has reached a state where it
can release the bus, it will. Now all of the signals normally
generated by the CPU (-MEMR, -MEMW, -IOR, -IOW and a few others) are
placed in a tri-stated condition (neither high or low) and then the
CPU asserts the HLDA signal which tells the DMA controller that it is
now in charge of the bus.</para>
<para>Depending on the processor, the CPU may be able to execute a few
additional instructions now that it no longer has the bus, but the CPU
will eventually have to wait when it reaches an instruction that must
read something from memory that is not in the internal processor cache
or pipeline.</para>
<para>Now that the DMA “is in charge”, the DMA activates its
-MEMR, -MEMW, -IOR, -IOW output signals, and the address outputs from
the DMA are set to 0x3456, which will be used to direct the byte that
is about to transferred to a specific memory location.</para>
<para>The DMA will then let the device that requested the DMA transfer
know that the transfer is commencing. This is done by asserting the
-DACK signal, or in the case of the floppy disk controller, -DACK2 is
asserted.</para>
<para>The floppy disk controller is now responsible for placing the byte
to be transferred on the bus Data lines. Unless the floppy controller
needs more time to get the data byte on the bus (and if the peripheral
does need more time it alerts the DMA via the READY signal), the DMA
will wait one DMA clock, and then de-assert the -MEMW and -IOR signals
so that the memory will latch and store the byte that was on the bus,
and the FDC will know that the byte has been transferred.</para>
<para>Since the DMA cycle only transfers a single byte at a time, the
FDC now drops the DRQ2 signal, so the DMA knows that it is no longer
needed. The DMA will de-assert the -DACK2 signal, so that the FDC
knows it must stop placing data on the bus.</para>
<para>The DMA will now check to see if any of the other DMA channels
have any work to do. If none of the channels have their DRQ lines
asserted, the DMA controller has completed its work and will now
tri-state the -MEMR, -MEMW, -IOR, -IOW and address signals.</para>
<para>Finally, the DMA will de-assert the HRQ signal. The CPU sees
this, and de-asserts the HOLDA signal. Now the CPU activates its
-MEMR, -MEMW, -IOR, -IOW and address lines, and it resumes executing
instructions and accessing main memory and the peripherals.</para>
<para>For a typical floppy disk sector, the above process is repeated
512 times, once for each byte. Each time a byte is transferred, the
address register in the DMA is incremented and the counter in the DMA
that shows how many bytes are to be transferred is decremented.</para>
<para>When the counter reaches zero, the DMA asserts the EOP signal,
which indicates that the counter has reached zero and no more data
will be transferred until the DMA controller is reprogrammed by the
CPU. This event is also called the Terminal Count (TC). There is only
one EOP signal, and since only DMA channel can be active at any
instant, the DMA channel that is currently active must be the DMA
channel that just completed its task.</para>
<para>If a peripheral wants to generate an interrupt when the transfer
of a buffer is complete, it can test for its -DACKn signal and the EOP
signal both being asserted at the same time. When that happens, it
means the DMA will not transfer any more information for that
peripheral without intervention by the CPU. The peripheral can then
assert one of the interrupt signals to get the processors' attention.
In the PC architecture, the DMA chip itself is not capable of
generating an interrupt. The peripheral and its associated hardware
is responsible for generating any interrupt that occurs.
Subsequently, it is possible to have a peripheral that uses DMA but
does not use interrupts.</para>
<para>It is important to understand that although the CPU always
releases the bus to the DMA when the DMA makes the request, this
action is invisible to both applications and the operating systems,
except for slight changes in the amount of time the processor takes to
execute instructions when the DMA is active. Subsequently, the
processor must poll the peripheral, poll the registers in the DMA
chip, or receive an interrupt from the peripheral to know for certain
when a DMA transfer has completed.</para>
</sect2>
<sect2>
<title>DMA Page Registers and 16Meg address space limitations</title>
<para>You may have noticed earlier that instead of the DMA setting the
address lines to 0x00123456 as we said earlier, the DMA only set
0x3456. The reason for this takes a bit of explaining.</para>
<para>When the original IBM PC was designed, IBM elected to use both DMA
and interrupt controller chips that were designed for use with the
8085, an 8-bit processor with an address space of 16 bits (64K).
Since the IBM PC supported more than 64K of memory, something had to
be done to allow the DMA to read or write memory locations above the
64K mark. What IBM did to solve this problem was to add an external
data latch for each DMA channel that holds the upper bits of the
address to be read to or written from. Whenever a DMA channel is
active, the contents of that latch are written to the address bus and
kept there until the DMA operation for the channel ends. IBM called
these latches “Page Registers”.</para>
<para>So for our example above, the DMA would put the 0x3456 part of the
address on the bus, and the Page Register for DMA channel 2 would put
0x0012xxxx on the bus. Together, these two values form the complete
address in memory that is to be accessed.</para>
<para>Because the Page Register latch is independent of the DMA chip,
the area of memory to be read or written must not span a 64K physical
boundary. For example, if the DMA accesses memory location 0xffff,
after that transfer the DMA will then increment the address register
and the DMA will access the next byte at location 0x0000, not 0x10000.
The results of letting this happen are probably not intended.</para>
<note>
<para>“Physical” 64K boundaries should not be confused
with 8086-mode 64K “Segments”, which are created by
mathematically adding a segment register with an offset register.
Page Registers have no address overlap and are mathematically OR-ed
together.</para>
</note>
<para>To further complicate matters, the external DMA address latches on
the PC/AT hold only eight bits, so that gives us 8+16=24 bits, which
means that the DMA can only point at memory locations between 0 and
16Meg. For newer computers that allow more than 16Meg of memory, the
standard PC-compatible DMA cannot access memory locations above
16Meg.</para>
<para>To get around this restriction, operating systems will reserve a
RAM buffer in an area below 16Meg that also does not span a physical
64K boundary. Then the DMA will be programmed to transfer data from
the peripheral and into that buffer. Once the DMA has moved the data
into this buffer, the operating system will then copy the data from
the buffer to the address where the data is really supposed to be
stored.</para>
<para>When writing data from an address above 16Meg to a DMA-based
peripheral, the data must be first copied from where it resides into a
buffer located below 16Meg, and then the DMA can copy the data from
the buffer to the hardware. In FreeBSD, these reserved buffers are
called “Bounce Buffers”. In the MS-DOS world, they are
sometimes called “Smart Buffers”.</para>
<note>
<para>A new implementation of the 8237, called the 82374, allows 16
bits of page register to be specified, allows access to the entire
32 bit address space, without the use of bounce buffers.</para>
</note>
</sect2>
<sect2>
<title>DMA Operational Modes and Settings</title>
<para>The 8237 DMA can be operated in several modes. The main ones
are:</para>
<variablelist>
<varlistentry>
<term>Single</term>
<listitem>
<para>A single byte (or word) is transferred. The DMA must
release and re-acquire the bus for each additional byte. This is
commonly-used by devices that cannot transfer the entire block
of data immediately. The peripheral will request the DMA each
time it is ready for another transfer.</para>
<para>The standard PC-compatible floppy disk controller (NEC 765)
only has a one-byte buffer, so it uses this mode.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Block/Demand</term>
<listitem>
<para>Once the DMA acquires the system bus, an entire block of
data is transferred, up to a maximum of 64K. If the peripheral
needs additional time, it can assert the READY signal to suspend
the transfer briefly. READY should not be used excessively, and
for slow peripheral transfers, the Single Transfer Mode should
be used instead.</para>
<para>The difference between Block and Demand is that once a Block
transfer is started, it runs until the transfer count reaches
zero. DRQ only needs to be asserted until -DACK is asserted.
Demand Mode will transfer one more bytes until DRQ is
de-asserted, at which point the DMA suspends the transfer and
releases the bus back to the CPU. When DRQ is asserted later,
the transfer resumes where it was suspended.</para>
<para>Older hard disk controllers used Demand Mode until CPU
speeds increased to the point that it was more efficient to
transfer the data using the CPU, particularly if the memory
locations used in the transfer were above the 16Meg mark.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Cascade</term>
<listitem>
<para>This mechanism allows a DMA channel to request the bus, but
then the attached peripheral device is responsible for placing
the addressing information on the bus instead of the DMA. This
is also used to implement a technique known as “Bus
Mastering”.</para>
<para>When a DMA channel in Cascade Mode receives control of the
bus, the DMA does not place addresses and I/O control signals on
the bus like the DMA normally does when it is active. Instead,
the DMA only asserts the -DACK signal for the active DMA
channel.</para>
<para>At this point it is up to the peripheral connected to that
DMA channel to provide address and bus control signals. The
peripheral has complete control over the system bus, and can do
reads and/or writes to any address below 16Meg. When the
peripheral is finished with the bus, it de-asserts the DRQ line,
and the DMA controller can then return control to the CPU or to
some other DMA channel.</para>
<para>Cascade Mode can be used to chain multiple DMA controllers
together, and this is exactly what DMA Channel 4 is used for in
the PC architecture. When a peripheral requests the bus on DMA
channels 0, 1, 2 or 3, the slave DMA controller asserts HLDREQ,
but this wire is actually connected to DRQ4 on the primary DMA
controller instead of to the CPU. The primary DMA controller,
thinking it has work to do on Channel 4, requests the bus from
the CPU using HLDREQ signal. Once the CPU grants the bus to the
primary DMA controller, -DACK4 is asserted, and that wire is
actually connected to the HLDA signal on the slave DMA
controller. The slave DMA controller then transfers data for
the DMA channel that requested it (0, 1, 2 or 3), or the slave
DMA may grant the bus to a peripheral that wants to perform its
own bus-mastering, such as a SCSI controller.</para>
<para>Because of this wiring arrangement, only DMA channels 0, 1,
2, 3, 5, 6 and 7 are usable with peripherals on PC/AT
systems.</para>
<note>
<para>DMA channel 0 was reserved for refresh operations in early
IBM PC computers, but is generally available for use by
peripherals in modern systems.</para>
</note>
<para>When a peripheral is performing Bus Mastering, it is
important that the peripheral transmit data to or from memory
constantly while it holds the system bus. If the peripheral
cannot do this, it must release the bus frequently so that the
system can perform refresh operations on main memory.</para>
<para>The Dynamic RAM used in all PCs for main memory must be
accessed frequently to keep the bits stored in the components
“charged”. Dynamic RAM essentially consists of
millions of capacitors with each one holding one bit of data.
These capacitors are charged with power to represent a
<literal>1</literal> or drained to represent a
<literal>0</literal>. Because all capacitors leak, power must
be added at regular intervals to keep the <literal>1</literal>
values intact. The RAM chips actually handle the task of
pumping power back into all of the appropriate locations in RAM,
but they must be told when to do it by the rest of the computer
so that the refresh activity won't interfere with the computer
wanting to access RAM normally. If the computer is unable to
refresh memory, the contents of memory will become corrupted in
just a few milliseconds.</para>
<para>Since memory read and write cycles “count” as
refresh cycles (a dynamic RAM refresh cycle is actually an
incomplete memory read cycle), as long as the peripheral
controller continues reading or writing data to sequential
memory locations, that action will refresh all of memory.</para>
<para>Bus-mastering is found in some SCSI host interfaces and
other high-performance peripheral controllers.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Autoinitialize</term>
<listitem>
<para>This mode causes the DMA to perform Byte, Block or Demand
transfers, but when the DMA transfer counter reaches zero, the
counter and address are set back to where they were when the DMA
channel was originally programmed. This means that as long as
the peripheral requests transfers, they will be granted. It is
up to the CPU to move new data into the fixed buffer ahead of
where the DMA is about to transfer it when doing output
operations, and read new data out of the buffer behind where the
DMA is writing when doing input operations.</para>
<para>This technique is frequently used on audio devices that have
small or no hardware “sample” buffers. There is
additional CPU overhead to manage this “circular”
buffer, but in some cases this may be the only way to eliminate
the latency that occurs when the DMA counter reaches zero and
the DMA stops transfers until it is reprogrammed.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2>
<title>Programming the DMA</title>
<para>The DMA channel that is to be programmed should always be
“masked” before loading any settings. This is because the
hardware might unexpectedly assert the DRQ for that channel, and the
DMA might respond, even though not all of the parameters have been
loaded or updated.</para>
<para>Once masked, the host must specify the direction of the transfer
(memory-to-I/O or I/O-to-memory), what mode of DMA operation is to be
used for the transfer (Single, Block, Demand, Cascade, etc), and
finally the address and length of the transfer are loaded. The length
that is loaded is one less than the amount you expect the DMA to
transfer. The LSB and MSB of the address and length are written to
the same 8-bit I/O port, so another port must be written to first to
guarantee that the DMA accepts the first byte as the LSB and the
second byte as the MSB of the length and address.</para>
<para>Then, be sure to update the Page Register, which is external to
the DMA and is accessed through a different set of I/O ports.</para>
<para>Once all the settings are ready, the DMA channel can be un-masked.
That DMA channel is now considered to be “armed”, and will
respond when the DRQ line for that channel is asserted.</para>
<para>Refer to a hardware data book for precise programming details for
the 8237. You will also need to refer to the I/O port map for the PC
system, which describes where the DMA and Page Register ports are
located. A complete port map table is located below.</para>
</sect2>
<sect2>
<title>DMA Port Map</title>
<para>All systems based on the IBM-PC and PC/AT have the DMA hardware
located at the same I/O ports. The complete list is provided below.
Ports assigned to DMA Controller #2 are undefined on non-AT
designs.</para>
<sect3>
<title>0x00–0x1f DMA Controller #1 (Channels 0, 1, 2 and
3)</title>
<para>DMA Address and Count Registers</para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0x00</entry>
<entry>write</entry>
<entry>Channel 0 starting address</entry>
</row>
<row>
<entry>0x00</entry>
<entry>read</entry>
<entry>Channel 0 current address</entry>
</row>
<row>
<entry>0x01</entry>
<entry>write</entry>
<entry>Channel 0 starting word count</entry>
</row>
<row>
<entry>0x01</entry>
<entry>read</entry>
<entry>Channel 0 remaining word count</entry>
</row>
<row>
<entry>0x02</entry>
<entry>write</entry>
<entry>Channel 1 starting address</entry>
</row>
<row>
<entry>0x02</entry>
<entry>read</entry>
<entry>Channel 1 current address</entry>
</row>
<row>
<entry>0x03</entry>
<entry>write</entry>
<entry>Channel 1 starting word count</entry>
</row>
<row>
<entry>0x03</entry>
<entry>read</entry>
<entry>Channel 1 remaining word count</entry>
</row>
<row>
<entry>0x04</entry>
<entry>write</entry>
<entry>Channel 2 starting address</entry>
</row>
<row>
<entry>0x04</entry>
<entry>read</entry>
<entry>Channel 2 current address</entry>
</row>
<row>
<entry>0x05</entry>
<entry>write</entry>
<entry>Channel 2 starting word count</entry>
</row>
<row>
<entry>0x05</entry>
<entry>read</entry>
<entry>Channel 2 remaining word count</entry>
</row>
<row>
<entry>0x06</entry>
<entry>write</entry>
<entry>Channel 3 starting address</entry>
</row>
<row>
<entry>0x06</entry>
<entry>read</entry>
<entry>Channel 3 current address</entry>
</row>
<row>
<entry>0x07</entry>
<entry>write</entry>
<entry>Channel 3 starting word count</entry>
</row>
<row>
<entry>0x07</entry>
<entry>read</entry>
<entry>Channel 3 remaining word count</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>DMA Command Registers</para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0x08</entry>
<entry>write</entry>
<entry>Command Register</entry>
</row>
<row>
<entry>0x08</entry>
<entry>read</entry>
<entry>Status Register</entry>
</row>
<row>
<entry>0x09</entry>
<entry>write</entry>
<entry>Request Register</entry>
</row>
<row>
<entry>0x09</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0a</entry>
<entry>write</entry>
<entry>Single Mask Register Bit</entry>
</row>
<row>
<entry>0x0a</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0b</entry>
<entry>write</entry>
<entry>Mode Register</entry>
</row>
<row>
<entry>0x0b</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0c</entry>
<entry>write</entry>
<entry>Clear LSB/MSB Flip-Flop</entry>
</row>
<row>
<entry>0x0c</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0d</entry>
<entry>write</entry>
<entry>Master Clear/Reset</entry>
</row>
<row>
<entry>0x0d</entry>
<entry>read</entry>
<entry>Temporary Register (not available on newer
versions)</entry>
</row>
<row>
<entry>0x0e</entry>
<entry>write</entry>
<entry>Clear Mask Register</entry>
</row>
<row>
<entry>0x0e</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0f</entry>
<entry>write</entry>
<entry>Write All Mask Register Bits</entry>
</row>
<row>
<entry>0x0f</entry>
<entry>read</entry>
<entry>Read All Mask Register Bits (only in Intel
82374)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0xc0–0xdf DMA Controller #2 (Channels 4, 5, 6 and
7)</title>
<para>DMA Address and Count Registers</para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0xc0</entry>
<entry>write</entry>
<entry>Channel 4 starting address</entry>
</row>
<row>
<entry>0xc0</entry>
<entry>read</entry>
<entry>Channel 4 current address</entry>
</row>
<row>
<entry>0xc2</entry>
<entry>write</entry>
<entry>Channel 4 starting word count</entry>
</row>
<row>
<entry>0xc2</entry>
<entry>read</entry>
<entry>Channel 4 remaining word count</entry>
</row>
<row>
<entry>0xc4</entry>
<entry>write</entry>
<entry>Channel 5 starting address</entry>
</row>
<row>
<entry>0xc4</entry>
<entry>read</entry>
<entry>Channel 5 current address</entry>
</row>
<row>
<entry>0xc6</entry>
<entry>write</entry>
<entry>Channel 5 starting word count</entry>
</row>
<row>
<entry>0xc6</entry>
<entry>read</entry>
<entry>Channel 5 remaining word count</entry>
</row>
<row>
<entry>0xc8</entry>
<entry>write</entry>
<entry>Channel 6 starting address</entry>
</row>
<row>
<entry>0xc8</entry>
<entry>read</entry>
<entry>Channel 6 current address</entry>
</row>
<row>
<entry>0xca</entry>
<entry>write</entry>
<entry>Channel 6 starting word count</entry>
</row>
<row>
<entry>0xca</entry>
<entry>read</entry>
<entry>Channel 6 remaining word count</entry>
</row>
<row>
<entry>0xcc</entry>
<entry>write</entry>
<entry>Channel 7 starting address</entry>
</row>
<row>
<entry>0xcc</entry>
<entry>read</entry>
<entry>Channel 7 current address</entry>
</row>
<row>
<entry>0xce</entry>
<entry>write</entry>
<entry>Channel 7 starting word count</entry>
</row>
<row>
<entry>0xce</entry>
<entry>read</entry>
<entry>Channel 7 remaining word count</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>DMA Command Registers</para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0xd0</entry>
<entry>write</entry>
<entry>Command Register</entry>
</row>
<row>
<entry>0xd0</entry>
<entry>read</entry>
<entry>Status Register</entry>
</row>
<row>
<entry>0xd2</entry>
<entry>write</entry>
<entry>Request Register</entry>
</row>
<row>
<entry>0xd2</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd4</entry>
<entry>write</entry>
<entry>Single Mask Register Bit</entry>
</row>
<row>
<entry>0xd4</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd6</entry>
<entry>write</entry>
<entry>Mode Register</entry>
</row>
<row>
<entry>0xd6</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd8</entry>
<entry>write</entry>
<entry>Clear LSB/MSB Flip-Flop</entry>
</row>
<row>
<entry>0xd8</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xda</entry>
<entry>write</entry>
<entry>Master Clear/Reset</entry>
</row>
<row>
<entry>0xda</entry>
<entry>read</entry>
<entry>Temporary Register (not present in Intel
82374)</entry>
</row>
<row>
<entry>0xdc</entry>
<entry>write</entry>
<entry>Clear Mask Register</entry>
</row>
<row>
<entry>0xdc</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xde</entry>
<entry>write</entry>
<entry>Write All Mask Register Bits</entry>
</row>
<row>
<entry>0xdf</entry>
<entry>read</entry>
<entry>Read All Mask Register Bits (only in Intel
82374)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0x80–0x9f DMA Page Registers</title>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0x87</entry>
<entry>r/w</entry>
<entry>Channel 0 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x83</entry>
<entry>r/w</entry>
<entry>Channel 1 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x81</entry>
<entry>r/w</entry>
<entry>Channel 2 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x82</entry>
<entry>r/w</entry>
<entry>Channel 3 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x8b</entry>
<entry>r/w</entry>
<entry>Channel 5 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x89</entry>
<entry>r/w</entry>
<entry>Channel 6 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x8a</entry>
<entry>r/w</entry>
<entry>Channel 7 Low byte (23-16) page Register</entry>
</row>
<row>
<entry>0x8f</entry>
<entry>r/w</entry>
<entry>Low byte page Refresh</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0x400–0x4ff 82374 Enhanced DMA Registers</title>
<para>The Intel 82374 EISA System Component (ESC) was introduced in
early 1996 and includes a DMA controller that provides a superset of
8237 functionality as well as other PC-compatible core peripheral
components in a single package. This chip is targeted at both EISA
and PCI platforms, and provides modern DMA features like
scatter-gather, ring buffers as well as direct access by the system
DMA to all 32 bits of address space.</para>
<para>If these features are used, code should also be included to
provide similar functionality in the previous 16 years worth of
PC-compatible computers. For compatibility reasons, some of the
82374 registers must be programmed <emphasis>after</emphasis>
programming the traditional 8237 registers for each transfer.
Writing to a traditional 8237 register forces the contents of some
of the 82374 enhanced registers to zero to provide backward software
compatibility.</para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry>0x401</entry>
<entry>r/w</entry>
<entry>Channel 0 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x403</entry>
<entry>r/w</entry>
<entry>Channel 1 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x405</entry>
<entry>r/w</entry>
<entry>Channel 2 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x407</entry>
<entry>r/w</entry>
<entry>Channel 3 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x4c6</entry>
<entry>r/w</entry>
<entry>Channel 5 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x4ca</entry>
<entry>r/w</entry>
<entry>Channel 6 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x4ce</entry>
<entry>r/w</entry>
<entry>Channel 7 High byte (bits 23-16) word count</entry>
</row>
<row>
<entry>0x487</entry>
<entry>r/w</entry>
<entry>Channel 0 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x483</entry>
<entry>r/w</entry>
<entry>Channel 1 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x481</entry>
<entry>r/w</entry>
<entry>Channel 2 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x482</entry>
<entry>r/w</entry>
<entry>Channel 3 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x48b</entry>
<entry>r/w</entry>
<entry>Channel 5 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x489</entry>
<entry>r/w</entry>
<entry>Channel 6 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x48a</entry>
<entry>r/w</entry>
<entry>Channel 6 High byte (bits 31-24) page Register</entry>
</row>
<row>
<entry>0x48f</entry>
<entry>r/w</entry>
<entry>High byte page Refresh</entry>
</row>
<row>
<entry>0x4e0</entry>
<entry>r/w</entry>
<entry>Channel 0 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4e1</entry>
<entry>r/w</entry>
<entry>Channel 0 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4e2</entry>
<entry>r/w</entry>
<entry>Channel 0 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4e4</entry>
<entry>r/w</entry>
<entry>Channel 1 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4e5</entry>
<entry>r/w</entry>
<entry>Channel 1 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4e6</entry>
<entry>r/w</entry>
<entry>Channel 1 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4e8</entry>
<entry>r/w</entry>
<entry>Channel 2 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4e9</entry>
<entry>r/w</entry>
<entry>Channel 2 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4ea</entry>
<entry>r/w</entry>
<entry>Channel 2 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4ec</entry>
<entry>r/w</entry>
<entry>Channel 3 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4ed</entry>
<entry>r/w</entry>
<entry>Channel 3 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4ee</entry>
<entry>r/w</entry>
<entry>Channel 3 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4f4</entry>
<entry>r/w</entry>
<entry>Channel 5 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4f5</entry>
<entry>r/w</entry>
<entry>Channel 5 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4f6</entry>
<entry>r/w</entry>
<entry>Channel 5 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4f8</entry>
<entry>r/w</entry>
<entry>Channel 6 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4f9</entry>
<entry>r/w</entry>
<entry>Channel 6 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4fa</entry>
<entry>r/w</entry>
<entry>Channel 6 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x4fc</entry>
<entry>r/w</entry>
<entry>Channel 7 Stop Register (bits 7-2)</entry>
</row>
<row>
<entry>0x4fd</entry>
<entry>r/w</entry>
<entry>Channel 7 Stop Register (bits 15-8)</entry>
</row>
<row>
<entry>0x4fe</entry>
<entry>r/w</entry>
<entry>Channel 7 Stop Register (bits 23-16)</entry>
</row>
<row>
<entry>0x40a</entry>
<entry>write</entry>
<entry>Channels 0-3 Chaining Mode Register</entry>
</row>
<row>
<entry>0x40a</entry>
<entry>read</entry>
<entry>Channel Interrupt Status Register</entry>
</row>
<row>
<entry>0x4d4</entry>
<entry>write</entry>
<entry>Channels 4-7 Chaining Mode Register</entry>
</row>
<row>
<entry>0x4d4</entry>
<entry>read</entry>
<entry>Chaining Mode Status</entry>
</row>
<row>
<entry>0x40c</entry>
<entry>read</entry>
<entry>Chain Buffer Expiration Control Register</entry>
</row>
<row>
<entry>0x410</entry>
<entry>write</entry>
<entry>Channel 0 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x411</entry>
<entry>write</entry>
<entry>Channel 1 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x412</entry>
<entry>write</entry>
<entry>Channel 2 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x413</entry>
<entry>write</entry>
<entry>Channel 3 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x415</entry>
<entry>write</entry>
<entry>Channel 5 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x416</entry>
<entry>write</entry>
<entry>Channel 6 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x417</entry>
<entry>write</entry>
<entry>Channel 7 Scatter-Gather Command Register</entry>
</row>
<row>
<entry>0x418</entry>
<entry>read</entry>
<entry>Channel 0 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x419</entry>
<entry>read</entry>
<entry>Channel 1 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x41a</entry>
<entry>read</entry>
<entry>Channel 2 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x41b</entry>
<entry>read</entry>
<entry>Channel 3 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x41d</entry>
<entry>read</entry>
<entry>Channel 5 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x41e</entry>
<entry>read</entry>
<entry>Channel 5 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x41f</entry>
<entry>read</entry>
<entry>Channel 7 Scatter-Gather Status Register</entry>
</row>
<row>
<entry>0x420-0x423</entry>
<entry>r/w</entry>
<entry>Channel 0 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x424-0x427</entry>
<entry>r/w</entry>
<entry>Channel 1 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x428-0x42b</entry>
<entry>r/w</entry>
<entry>Channel 2 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x42c-0x42f</entry>
<entry>r/w</entry>
<entry>Channel 3 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x434-0x437</entry>
<entry>r/w</entry>
<entry>Channel 5 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x438-0x43b</entry>
<entry>r/w</entry>
<entry>Channel 6 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x43c-0x43f</entry>
<entry>r/w</entry>
<entry>Channel 7 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
</sect2>
</sect1>
<sect1 id="internals-vm">
<title>The FreeBSD VM System</title>
<para><emphasis>Contributed by &a.dillon;. 6 Feb 1999</emphasis></para>
<sect2>
<title>Management of physical
memory—<literal>vm_page_t</literal></title>
<para>Physical memory is managed on a page-by-page basis through the
<literal>vm_page_t</literal> structure. Pages of physical memory are
categorized through the placement of their respective
<literal>vm_page_t</literal> structures on one of several paging
queues.</para>
<para>A page can be in a wired, active, inactive, cache, or free state.
Except for the wired state, the page is typically placed in a doubly
link list queue representing the state that it is in. Wired pages
are not placed on any queue.</para>
<para>FreeBSD implements a more involved paging queue for cached and
free pages in order to implement page coloring. Each of these states
involves multiple queues arranged according to the size of the
processor's L1 and L2 caches. When a new page needs to be allocated,
FreeBSD attempts to obtain one that is reasonably well aligned from
the point of view of the L1 and L2 caches relative to the VM object
the page is being allocated for.</para>
<para>Additionally, a page may be held with a reference count or locked
with a busy count. The VM system also implements an “ultimate
locked” state for a page using the PG_BUSY bit in the page's
flags.</para>
<para>In general terms, each of the paging queues operates in a LRU
fashion. A page is typically placed in a wired or active state
initially. When wired, the page is usually associated with a page
table somewhere. The VM system ages the page by scanning pages in a
more active paging queue (LRU) in order to move them to a less-active
paging queue. Pages that get moved into the cache are still
associated with a VM object but are candidates for immediate reuse.
Pages in the free queue are truly free. FreeBSD attempts to minimize
the number of pages in the free queue, but a certain minimum number of
truly free pages must be maintained in order to accommodate page
allocation at interrupt time.</para>
<para>If a process attempts to access a page that does not exist in its
page table but does exist in one of the paging queues ( such as the
inactive or cache queues), a relatively inexpensive page reactivation
fault occurs which causes the page to be reactivated. If the page
does not exist in system memory at all, the process must block while
the page is brought in from disk.</para>
<para>FreeBSD dynamically tunes its paging queues and attempts to
maintain reasonable ratios of pages in the various queues as well as
attempts to maintain a reasonable breakdown of clean vs dirty pages.
The amount of rebalancing that occurs depends on the system's memory
load. This rebalancing is implemented by the pageout daemon and
involves laundering dirty pages (syncing them with their backing
store), noticing when pages are activity referenced (resetting their
position in the LRU queues or moving them between queues), migrating
pages between queues when the queues are out of balance, and so forth.
FreeBSD's VM system is willing to take a reasonable number of
reactivation page faults to determine how active or how idle a page
actually is. This leads to better decisions being made as to when to
launder or swap-out a page.</para>
</sect2>
<sect2>
<title>The unified buffer
cache—<literal>vm_object_t</literal></title>
<para>FreeBSD implements the idea of a generic “VM object”.
VM objects can be associated with backing store of various
types—unbacked, swap-backed, physical device-backed, or
file-backed storage. Since the filesystem uses the same VM objects to
manage in-core data relating to files, the result is a unified buffer
cache.</para>
<para>VM objects can be <emphasis>shadowed</emphasis>. That is, they
can be stacked on top of each other. For example, you might have a
swap-backed VM object stacked on top of a file-backed VM object in
order to implement a MAP_PRIVATE mmap()ing. This stacking is also
used to implement various sharing properties, including,
copy-on-write, for forked address spaces.</para>
<para>It should be noted that a <literal>vm_page_t</literal> can only be
associated with one VM object at a time. The VM object shadowing
implements the perceived sharing of the same page across multiple
instances.</para>
</sect2>
<sect2>
<title>Filesystem I/O—<literal>struct buf</literal></title>
<para>vnode-backed VM objects, such as file-backed objects, generally
need to maintain their own clean/dirty info independent from the VM
system's idea of clean/dirty. For example, when the VM system decides
to synchronize a physical page to its backing store, the VM system
needs to mark the page clean before the page is actually written to
its backing s tore. Additionally, filesystems need to be able to map
portions of a file or file metadata into KVM in order to operate on
it.</para>
<para>The entities used to manage this are known as filesystem buffers,
<literal>struct buf</literal>'s, and also known as
<literal>bp</literal>'s. When a filesystem needs to operate on a
portion of a VM object, it typically maps part of the object into a
struct buf and the maps the pages in the struct buf into KVM. In the
same manner, disk I/O is typically issued by mapping portions of
objects into buffer structures and then issuing the I/O on the buffer
structures. The underlying vm_page_t's are typically busied for the
duration of the I/O. Filesystem buffers also have their own notion of
being busy, which is useful to filesystem driver code which would
rather operate on filesystem buffers instead of hard VM pages.</para>
<para>FreeBSD reserves a limited amount of KVM to hold mappings from
struct bufs, but it should be made clear that this KVM is used solely
to hold mappings and does not limit the ability to cache data.
Physical data caching is strictly a function of
<literal>vm_page_t</literal>'s, not filesystem buffers. However,
since filesystem buffers are used placehold I/O, they do inherently
limit the amount of concurrent I/O possible. As there are usually a
few thousand filesystem buffers available, this is not usually a
problem.</para>
</sect2>
<sect2>
<title>Mapping Page Tables - vm_map_t, vm_entry_t</title>
<para>FreeBSD separates the physical page table topology from the VM
system. All hard per-process page tables can be reconstructed on the
fly and are usually considered throwaway. Special page tables such as
those managing KVM are typically permanently preallocated. These page
tables are not throwaway.</para>
<para>FreeBSD associates portions of vm_objects with address ranges in
virtual memory through <literal>vm_map_t</literal> and
<literal>vm_entry_t</literal> structures. Page tables are directly
synthesized from the
<literal>vm_map_t</literal>/<literal>vm_entry_t</literal>/
<literal>vm_object_t</literal> hierarchy. Remember when I mentioned
that physical pages are only directly associated with a
<literal>vm_object</literal>. Well, that isn't quite true.
<literal>vm_page_t</literal>'s are also linked into page tables that
they are actively associated with. One <literal>vm_page_t</literal>
can be linked into several <emphasis>pmaps</emphasis>, as page tables
are called. However, the hierarchical association holds so all
references to the same page in the same object reference the same
<literal>vm_page_t</literal> and thus give us buffer cache unification
across the board.</para>
</sect2>
<sect2>
<title>KVM Memory Mapping</title>
<para>FreeBSD uses KVM to hold various kernel structures. The single
largest entity held in KVM is the filesystem buffer cache. That is,
mappings relating to <literal>struct buf</literal> entities.</para>
<para>Unlike Linux, FreeBSD does NOT map all of physical memory into
KVM. This means that FreeBSD can handle memory configurations up to
4G on 32 bit platforms. In fact, if the mmu were capable of it,
FreeBSD could theoretically handle memory configurations up to 8TB on
a 32 bit platform. However, since most 32 bit platforms are only
capable of mapping 4GB of ram, this is a moot point.</para>
<para>KVM is managed through several mechanisms. The main mechanism
used to manage KVM is the <emphasis>zone allocator</emphasis>. The
zone allocator takes a chunk of KVM and splits it up into
constant-sized blocks of memory in order to allocate a specific type
of structure. You can use <command>vmstat -m</command> to get an
overview of current KVM utilization broken down by zone.</para>
</sect2>
<sect2>
<title>Tuning the FreeBSD VM system</title>
<para>A concerted effort has been made to make the FreeBSD kernel
dynamically tune itself. Typically you do not need to mess with
anything beyond the <literal>maxusers</literal> and
<literal>NMBCLUSTERS</literal> kernel config options. That is, kernel
compilation options specified in (typically)
<filename>/usr/src/sys/i386/conf/<replaceable>CONFIG_FILE</replaceable></filename>.
A description of all available kernel configuration options can be
found in <filename>/usr/src/sys/i386/conf/LINT</filename>.</para>
<para>In a large system configuration you may wish to increase
<literal>maxusers</literal>. Values typically range from 10 to 128.
Note that raising <literal>maxusers</literal> too high can cause the
system to overflow available KVM resulting in unpredictable operation.
It is better to leave maxusers at some reasonable number and add other
options, such as <literal>NMBCLUSTERS</literal>, to increase specific
resources.</para>
<para>If your system is going to use the network heavily, you may want
to increase <literal>NMBCLUSTERS</literal>. Typical values range from
1024 to 4096.</para>
<para>The <literal>NBUF</literal> parameter is also traditionally used
to scale the system. This parameter determines the amount of KVA the
system can use to map filesystem buffers for I/O. Note that this
parameter has nothing whatsoever to do with the unified buffer cache!
This parameter is dynamically tuned in 3.0-CURRENT and later kernels
and should generally not be adjusted manually. We recommend that you
<emphasis>not</emphasis> try to specify an <literal>NBUF</literal>
parameter. Let the system pick it. Too small a value can result in
extremely inefficient filesystem operation while too large a value can
starve the page queues by causing too many pages to become wired
down.</para>
<para>By default, FreeBSD kernels are not optimized. You can set
debugging and optimization flags with the
<literal>makeoptions</literal> directive in the kernel configuration.
Note that you should not use <option>-g</option> unless you can
accommodate the large (typically 7 MB+) kernels that result.</para>
<programlisting>makeoptions DEBUG="-g"
makeoptions COPTFLAGS="-O2 -pipe"</programlisting>
<para>Sysctl provides a way to tune kernel parameters at run-time. You
typically do not need to mess with any of the sysctl variables,
especially the VM related ones.</para>
<para>Run time VM and system tuning is relatively straightforward.
First, use softupdates on your UFS/FFS filesystems whenever possible.
<filename>/usr/src/contrib/sys/softupdates/README</filename> contains
instructions (and restrictions) on how to configure it up.</para>
<para>Second, configure sufficient swap. You should have a swap
partition configured on each physical disk, up to four, even on your
“work” disks. You should have at least 2x the swap space
as you have main memory, and possibly even more if you do not have a
lot of memory. You should also size your swap partition based on the
maximum memory configuration you ever intend to put on the machine so
you do not have to repartition your disks later on. If you want to be
able to accommodate a crash dump, your first swap partition must be at
least as large as main memory and <filename>/var/crash</filename> must
have sufficient free space to hold the dump.</para>
<para>NFS-based swap is perfectly acceptable on -4.x or later systems,
but you must be aware that the NFS server will take the brunt of the
paging load.</para>
</sect2>
</sect1>
+
+ <sect1 id="ipv6-implementation">
+ <title>IPv6/IPsec implementation</title>
+
+ <para><emphasis>Contributed by &a.shin;, 5 March
+ 2000.</emphasis></para>
+
+ <para>This section should explain IPv6 and IPsec related implementation
+ internals. These functionalities are derived from <ulink
+ url="http://www.kame.net">KAME project</ulink></para>
+
+ <sect2 id="ipv6">
+ <title>IPv6</title>
+
+ <sect3>
+ <title>Conformance</title>
+
+ <para>The IPv6 related functions conforms, or tries to conform to
+ the latest set of IPv6 specifications. For future reference we list
+ some of the relevant documents below (<emphasis>NOTE</emphasis>: this
+ is not a complete list - this is too hard to maintain...).</para>
+
+ <para>For details please refer to specific chapter in the document,
+ RFCs, manpages, or comments in the source code.</para>
+
+ <para>Conformance tests have been performed on the KAME STABLE kit
+ at TAHI project. Results can be viewed at <ulink
+ url="http://www.tahi.org/report/KAME/">http://www.tahi.org/report/KAME/
+ </ulink>. We also attended Univ. of New Hampshire IOL tests (<ulink
+ url="http://www.iol.unh.edu/">http://www.iol.unh.edu/</ulink>) in the
+ past, with our past snapshots.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>RFC1639: FTP Operation Over Big Address Records
+ (FOOBAR)</para>
+ <itemizedlist>
+ <listitem>
+ <para>RFC2428 is preferred over RFC1639. FTP clients will
+ first try RFC2428, then RFC1639 if failed.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC1886: DNS Extensions to support IPv6</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC1933: Transition Mechanisms for IPv6 Hosts and
+ Routers</para>
+ <itemizedlist>
+ <listitem>
+ <para>IPv4 compatible address is not supported.</para>
+ </listitem>
+ <listitem>
+ <para>automatic tunneling (described in 4.3 of this RFC) is not
+ supported.</para>
+ </listitem>
+ <listitem>
+ <para>&man.gif.4; interface implements IPv[46]-over-IPv[46]
+ tunnel in a generic way, and it covers "configured tunnel"
+ described in the spec. See <link linkend="gif">23.5.1.5</link>
+ in this document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC1981: Path MTU Discovery for IPv6</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2080: RIPng for IPv6</para>
+ <itemizedlist>
+ <listitem>
+ <para>usr.sbin/route6d support this.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2292: Advanced Sockets API for IPv6</para>
+ <itemizedlist>
+ <listitem>
+ <para>For supported library functions/kernel APIs, see
+ <filename>sys/netinet6/ADVAPI</filename>.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2362: Protocol Independent Multicast-Sparse
+ Mode (PIM-SM)</para>
+ <itemizedlist>
+ <listitem>
+ <para>RFC2362 defines packet formats for PIM-SM.
+ <filename>draft-ietf-pim-ipv6-01.txt</filename> is
+ written based on this.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2373: IPv6 Addressing Architecture</para>
+ <itemizedlist>
+ <listitem>
+ <para>supports node required addresses, and conforms to
+ the scope requirement.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2374: An IPv6 Aggregatable Global Unicast Address
+ Format</para>
+ <itemizedlist>
+ <listitem>
+ <para>supports 64-bit length of Interface ID.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2375: IPv6 Multicast Address Assignments</para>
+ <itemizedlist>
+ <listitem>
+ <para>Userland applications use the well-known addresses
+ assigned in the RFC.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2428: FTP Extensions for IPv6 and NATs</para>
+ <itemizedlist>
+ <listitem>
+ <para>RFC2428 is preferred over RFC1639. ftp clients will
+ first try RFC2428, then RFC1639 if failed.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2460: IPv6 specification</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2461: Neighbor discovery for IPv6</para>
+ <itemizedlist>
+ <listitem>
+ <para>See <link linkend="neighbor-discovery">23.5.1.2</link>
+ in this document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2462: IPv6 Stateless Address Autoconfiguration</para>
+ <itemizedlist>
+ <listitem>
+ <para>See <link linkend="ipv6-pnp">23.5.1.4</link> in this
+ document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2463: ICMPv6 for IPv6 specification</para>
+ <itemizedlist>
+ <listitem>
+ <para>See <link linkend="icmpv6">23.5.1.9</link> in this
+ document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2464: Transmission of IPv6 Packets over Ethernet
+ Networks</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2465: MIB for IPv6: Textual Conventions and General
+ Group</para>
+ <itemizedlist>
+ <listitem>
+ <para>Necessary statistics are gathered by the kernel. Actual
+ IPv6 MIB support is provided as patchkit for ucd-snmp.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2466: MIB for IPv6: ICMPv6 group</para>
+ <itemizedlist>
+ <listitem>
+ <para>Necessary statistics are gathered by the kernel. Actual
+ IPv6 MIB support is provided as patchkit for ucd-snmp.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2467: Transmission of IPv6 Packets over FDDI
+ Networks</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2497: Transmission of IPv6 packet over ARCnet
+ Networks</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2553: Basic Socket Interface Extensions for IPv6</para>
+ <itemizedlist>
+ <listitem>
+ <para>IPv4 mapped address (3.7) and special behavior of IPv6
+ wildcard bind socket (3.8) are supported. See <link
+ linkend="ipv6-wildcard-socket">23.5.1.12</link>
+ in this document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2675: IPv6 Jumbograms</para>
+ <itemizedlist>
+ <listitem>
+ <para>See <link linkend="ipv6-jumbo">23.5.1.7</link> in
+ this document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>RFC2710: Multicast Listener Discovery for IPv6</para>
+ </listitem>
+
+ <listitem>
+ <para>RFC2711: IPv6 router alert option</para>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-ietf-ipngwg-router-renum-08</filename>: Router
+ renumbering for IPv6</para>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-ietf-ipngwg-icmp-namelookups-02</filename>:
+ IPv6 Name Lookups Through ICMP</para>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-ietf-ipngwg-icmp-name-lookups-03</filename>:
+ IPv6 Name Lookups Through ICMP</para>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-ietf-pim-ipv6-01.txt</filename>:
+ PIM for IPv6</para>
+ <itemizedlist>
+ <listitem>
+ <para>&man.pim6dd.8; implements dense mode. &man.pim6sd.8;
+ implements sparse mode.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-itojun-ipv6-tcp-to-anycast-00</filename>:
+ Disconnecting TCP connection toward IPv6 anycast address</para>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-yamamoto-wideipv6-comm-model-00</filename>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>See <link linkend="ipv6-sas">23.5.1.6</link> in this
+ document for details.</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para><filename>draft-ietf-ipngwg-scopedaddr-format-00.txt
+ </filename>: An Extension of Format for IPv6 Scoped
+ Addresses</para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+
+ <sect3 id="neighbor-discovery">
+ <title>Neighbor Discovery</title>
+
+ <para>Neighbor Discovery is fairly stable. Currently Address
+ Resolution, Duplicated Address Detection, and Neighbor Unreachability
+ Detection are supported. In the near future we will be adding Proxy
+ Neighbor Advertisement support in the kernel and Unsolicited Neighbor
+ Advertisement transmission command as admin tool.</para>
+
+ <para>If DAD fails, the address will be marked "duplicated" and
+ message will be generated to syslog (and usually to console). The
+ "duplicated" mark can be checked with &man.ifconfig.8;. It is
+ administrators' responsibility to check for and recover from DAD
+ failures. The behavior should be improved in the near future.</para>
+
+ <para>Some of the network driver loops multicast packets back to itself,
+ even if instructed not to do so (especially in promiscuous mode).
+ In such cases DAD may fail, because DAD engine sees inbound NS packet
+ (actually from the node itself) and considers it as a sign of duplicate.
+ You may want to look at #if condition marked "heuristics" in
+ sys/netinet6/nd6_nbr.c:nd6_dad_timer() as workaround (note that the code
+ fragment in "heuristics" section is not spec conformant).</para>
+
+ <para>Neighbor Discovery specification (RFC2461) does not talk about
+ neighbor cache handling in the following cases:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>when there was no neighbor cache entry, node
+ received unsolicited RS/NS/NA/redirect packet without
+ link-layer address</para>
+ </listitem>
+ <listitem>
+ <para>neighbor cache handling on medium without link-layer
+ address (we need a neighbor cache entry for IsRouter bit)</para>
+ </listitem>
+ </orderedlist>
+
+ <para>For first case, we implemented workaround based on discussions
+ on IETF ipngwg mailing list. For more details, see the comments in
+ the source code and email thread started from (IPng 7155), dated
+ Feb 6 1999.</para>
+
+ <para>IPv6 on-link determination rule (RFC2461) is quite different
+ from assumptions in BSD network code. At this moment, no on-link
+ determination rule is supported where default router list is empty
+ (RFC2461, section 5.2, last sentence in 2nd paragraph - note that
+ the spec misuse the word "host" and "node" in several places in
+ the section).</para>
+
+ <para>To avoid possible DoS attacks and infinite loops, only 10
+ options on ND packet is accepted now. Therefore, if you have 20
+ prefix options attached to RA, only the first 10 prefixes will be
+ recognized. If this troubles you, please ask it on FREEBSD-CURRENT
+ mailing list and/or modify nd6_maxndopt in
+ <filename>sys/netinet6/nd6.c</filename>. If there are high demands
+ we may provide sysctl knob for the variable.</para>
+ </sect3>
+
+ <sect3 id="ipv6-scope-index">
+ <title>Scope Index</title>
+
+ <para>IPv6 uses scoped addresses. Therefore, it is very important to
+ specify scope index (interface index for link-local address, or
+ site index for site-local address) with an IPv6 address. Without
+ scope index, scoped IPv6 address is ambiguous to the kernel, and
+ kernel will not be able to determine the outbound interface for a
+ packet.</para>
+
+ <para>Ordinary userland applications should use advanced API
+ (RFC2292) to specify scope index, or interface index. For similar
+ purpose, sin6_scope_id member in sockaddr_in6 structure is defined
+ in RFC2553. However, the semantics for sin6_scope_id is rather vague.
+ If you care about portability of your application, we suggest you to
+ use advanced API rather than sin6_scope_id.</para>
+
+ <para>In the kernel, an interface index for link-local scoped address is
+ embedded into 2nd 16bit-word (3rd and 4th byte) in IPv6 address. For
+ example, you may see something like:
+ </para>
+
+ <screen>
+ fe80:1::200:f8ff:fe01:6317
+ </screen>
+
+ <para>in the routing table and interface address structure (struct
+ in6_ifaddr). The address above is a link-local unicast address
+ which belongs to a network interface whose interface identifier is 1.
+ The embedded index enables us to identify IPv6 link local
+ addresses over multiple interfaces effectively and with only a
+ little code change.</para>
+
+ <para>Routing daemons and configuration programs, like &man.route6d.8;
+ and &man.ifconfig.8;, will need to manipulate the "embedded" scope
+ index. These programs use routing sockets and ioctls (like
+ SIOCGIFADDR_IN6) and the kernel API will return IPv6 addresses with
+ 2nd 16bit-word filled in. The APIs are for manipulating kernel
+ internal structure. Programs that use these APIs have to be prepared
+ about differences in kernels anyway.</para>
+
+ <para>When you specify scoped address to the command line, NEVER write
+ the embedded form (such as ff02:1::1 or fe80:2::fedc). This is not
+ supposed to work. Always use standard form, like ff02::1 or
+ fe80::fedc, with command line option for specifying interface (like
+ <command>ping6 -I ne0 ff02::1</command>). In general, if a command
+ does not have command line option to specify outgoing interface, that
+ command is not ready to accept scoped address. This may seem to be
+ opposite from IPv6's premise to support "dentist office" situation.
+ We believe that specifications need some improvements for this.</para>
+
+ <para>Some of the userland tools support extended numeric IPv6 syntax,
+ as documented in
+ <filename>draft-ietf-ipngwg-scopedaddr-format-00.txt</filename>. You
+ can specify outgoing link, by using name of the outgoing interface
+ like "fe80::1%ne0". This way you will be able to specify link-local
+ scoped address without much trouble.</para>
+
+ <para>To use this extension in your program, you'll need to use
+ &man.getaddrinfo.3;, and &man.getnameinfo.3; with NI_WITHSCOPEID.
+ The implementation currently assumes 1-to-1 relationship between a
+ link and an interface, which is stronger than what specs say.</para>
+ </sect3>
+
+ <sect3 id="ipv6-pnp">
+ <title>Plug and Play</title>
+
+ <para>Most of the IPv6 stateless address autoconfiguration is implemeted
+ in the kernel. Neighbor Discovery functions are implemented in the
+ kernel as a whole. Router Advertisement (RA) input for hosts is
+ implemented in the kernel. Router Solicitation (RS) output for
+ endhosts, RS input for routers, and RA output for routers are
+ implemented in the userland.</para>
+
+ <sect4>
+ <title>Assignment of link-local, and special addresses</title>
+
+ <para>IPv6 link-local address is generated from IEEE802 adddress
+ (ethernet MAC address). Each of interface is assigned an IPv6
+ link-local address automatically, when the interface becomes up
+ (IFF_UP). Also, direct route for the link-local address is added
+ to routing table.</para>
+
+ <para>Here is an output of netstat command:</para>
+
+<screen>
+Internet6:
+Destination Gateway Flags Netif Expire
+fe80:1::%ed0/64 link#1 UC ed0
+fe80:2::%ep0/64 link#2 UC ep0
+</screen>
+
+ <para>Interfaces that has no IEEE802 address (pseudo interfaces
+ like tunnel interfaces, or ppp interfaces) will borrow IEEE802
+ address from other interfaces, such as ethernet interfaces,
+ whenever possible. If there is no IEEE802 hardware attached,
+ last-resort pseudorandom value, which is from MD5(hostname), will
+ be used as source of link-local address. If it is not suitable
+ for your usage, you will need to configure the link-local address
+ manually.</para>
+
+ <para>If an interface is not capable of handling IPv6 (such as
+ lack of multicast support), link-local address will not be
+ assigned to that interface. See section 2 for details.</para>
+
+ <para>Each interface joins the solicited multicast address and the
+ link-local all-nodes multicast addresses (e.g. fe80::1:ff01:6317
+ and ff02::1, respectively, on the link the interface is attached).
+ In addition to a link-local address, the loopback address (::1)
+ will be assigned to the loopback interface. Also, ::1/128 and
+ ff01::/32 are automatically added to routing table, and loopback
+ interface joins node-local multicast group ff01::1.</para>
+ </sect4>
+
+ <sect4>
+ <title>Stateless address autoconfiguration on hosts</title>
+
+ <para>In IPv6 specification, nodes are separated into two categories:
+ <emphasis>routers</emphasis> and <emphasis>hosts</emphasis>. Routers
+ forward packets addressed to others, hosts does not forward the
+ packets. net.inet6.ip6.forwarding defines whether this node is
+ router or host (router if it is 1, host if it is 0).</para>
+
+ <para>When a host hears Router Advertisement from the router, a host
+ may autoconfigure itself by stateless address autoconfiguration.
+ This behavior can be controlled by net.inet6.ip6.accept_rtadv (host
+ autoconfigures itself if it is set to 1). By autoconfiguration,
+ network address prefix for the receiving interface (usually global
+ address prefix) is added. Default route is also configured.
+ Routers periodically generate Router Advertisement packets. To
+ request an adjacent router to generate RA packet, a host can
+ transmit Router Solicitation. To generate a RS packet at any time,
+ use the <emphasis>rtsol</emphasis> command. &man.rtsold.8; daemon is
+ also available. &man.rtsold.8; generates Router Solicitation whenever
+ necessary, and it works great for nomadic usage (notebooks/laptops).
+ If one wishes to ignore Router Advertisements, use sysctl to set
+ net.inet6.ip6.accept_rtadv to 0.</para>
+
+ <para>To generate Router Advertisement from a router, use the
+ &man.rtadvd.8 daemon.</para>
+
+ <para>Note that, IPv6 specification assumes the following items, and
+ nonconforming cases are left unspecified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Only hosts will listen to router advertisements</para>
+ </listitem>
+ <listitem>
+ <para>Hosts have single network interface (except loopback)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Therefore, this is unwise to enable net.inet6.ip6.accept_rtadv
+ on routers, or multi-interface host. A misconfigured node can
+ behave strange (nonconforming configuration allowed for those who
+ would like to do some experiments).</para>
+
+ <para>To summarize the sysctl knob:</para>
+
+ <screen>
+ accept_rtadv forwarding role of the node
+ --- --- ---
+ 0 0 host (to be manually configured)
+ 0 1 router
+ 1 0 autoconfigured host
+ (spec assumes that host has single
+ interface only, autoconfigured host
+ with multiple interface is
+ out-of-scope)
+ 1 1 invalid, or experimental
+ (out-of-scope of spec)
+ </screen>
+
+ <para>RFC2462 has validation rule against incoming RA prefix
+ information option, in 5.5.3 (e). This is to protect hosts from
+ malicious (or misconfigured) routers that advertise very short
+ prefix lifetime. There was an update from Jim Bound to ipngwg
+ mailing list (look for "(ipng 6712)" in the archive) and it is
+ implemented Jim's update.</para>
+
+ <para>See <link linkend="neighbor-discovery">23.5.1.2</link> in
+ the document for relationship between DAD and
+ autoconfiguration.</para>
+ </sect4>
+ </sect3>
+
+ <sect3 id="gif">
+ <title>Generic tunnel interface</title>
+
+ <para>GIF (Generic InterFace) is a pseudo interface for configured
+ tunnel. Details are described in &man.gif.4; manpage. Currently</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>v6 in v6</para>
+ </listitem>
+ <listitem>
+ <para>v6 in v4</para>
+ </listitem>
+ <listitem>
+ <para>v4 in v6</para>
+ </listitem>
+ <listitem>
+ <para>v4 in v4</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>are available. Use &man.gifconfig.8; to assign physical (outer)
+ source and destination address to gif interfaces. Configuration that
+ uses same address family for inner and outer IP header (v4 in v4, or
+ v6 in v6) is dangerous. It is very easy to configure interfaces and
+ routing tables to perform infinite level of tunneling.
+ <emphasis>Please be warned</emphasis>.</para>
+
+ <para>gif can be configured to be ECN-friendly. See <link
+ linkend="ipsec-ecn">23.5.4.5</link> for ECN-friendliness of
+ tunnels, and &man.gif.4; manpage for how to configure.</para>
+
+ <para>If you would like to configure an IPv4-in-IPv6 tunnel with gif
+ interface, read &man.gif.4; manpage carefully. You will need to
+ remove IPv6 link-local address automatically assigned to the gif
+ interface.</para>
+ </sect3>
+
+ <sect3 id="ipv6-sas">
+ <title>Source Address Selection</title>
+
+ <para>Current source selection rule is scope oriented (there are some
+ exceptions - see below). For a given destination, a source IPv6
+ address is selected by the following rule:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>If the source address is explicitly specified by
+ the user (e.g. via the advanced API), the specified address
+ is used.</para>
+ </listitem>
+
+ <listitem>
+ <para>If there is an address assigned to the outgoing
+ interface (which is usually determined by looking up the
+ routing table) that has the same scope as the destination
+ address, the address is used.</para>
+
+ <para>This is the most typical case.</para>
+ </listitem>
+
+ <listitem>
+ <para>If there is no address that satisfies the above
+ condition, choose a global address assigned to one of
+ the interfaces on the sending node.</para>
+ </listitem>
+
+ <listitem>
+ <para>If there is no address that satisfies the above condition,
+ and destination address is site local scope, choose a site local
+ address assigned to one of the interfaces on the sending node.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>If there is no address that satisfies the above condition,
+ choose the address associated with the routing table entry for the
+ destination. This is the last resort, which may cause scope
+ violation.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>For instance, ::1 is selected for ff01::1,
+ fe80:1::200:f8ff:fe01:6317 for fe80:1::2a0:24ff:feab:839b (note
+ that embedded interface index - described in <link
+ linkend="ipv6-scope-index">23.5.1.3</link> - helps us
+ choose the right source address. Those embedded indices will not
+ be on the wire). If the outgoing interface has multiple address for
+ the scope, a source is selected longest match basis (rule 3). Suppose
+ 3ffe:501:808:1:200:f8ff:fe01:6317 and 3ffe:2001:9:124:200:f8ff:fe01:6317
+ are given to the outgoing interface. 3ffe:501:808:1:200:f8ff:fe01:6317
+ is chosen as the source for the destination 3ffe:501:800::1.</para>
+
+ <para>Note that the above rule is not documented in the IPv6 spec.
+ It is considered "up to implementation" item. There are some cases
+ where we do not use the above rule. One example is connected TCP
+ session, and we use the address kept in tcb as the source. Another
+ example is source address for Neighbor Advertisement. Under the spec
+ (RFC2461 7.2.2) NA's source should be the target address of the
+ corresponding NS's target. In this case we follow the spec rather
+ than the above longest-match rule.</para>
+
+ <para>For new connections (when rule 1 does not apply), deprecated
+ addresses (addresses with preferred lifetime = 0) will not be chosen
+ as source address if other choises are available. If no other choices
+ are available, deprecated address will be used as a last resort. If
+ there are multiple choice of deprecated addresses, the above scope
+ rule will be used to choose from those deprecated addreses. If you
+ would like to prohibit the use of deprecated address for some reason,
+ configure net.inet6.ip6.use_deprecated to 0. The issue related to
+ deprecated address is described in RFC2462 5.5.4 (NOTE: there is
+ some debate underway in IETF ipngwg on how to use "deprecated"
+ address).</para>
+ </sect3>
+
+ <sect3 id="ipv6-jumbo">
+ <title>Jumbo Payload</title>
+
+ <para>The Jumbo Payload hop-by-hop option is implemented and can
+ be used to send IPv6 packets with payloads longer than 65,535 octets.
+ But currently no physical interface whose MTU is more than 65,535 is
+ supported, so such payloads can be seen only on the loopback
+ interface (i.e. lo0).</para>
+
+ <para>If you want to try jumbo payloads, you first have to reconfigure
+ the kernel so that the MTU of the loopback interface is more than
+ 65,535 bytes; add the following to the kernel configuration file:</para>
+
+ <para><literal>
+ options "LARGE_LOMTU" #To test jumbo payload
+ </literal></para>
+
+ <para>and recompile the new kernel.</para>
+
+ <para>Then you can test jumbo payloads by the &man.ping6.8; command
+ with -b and -s options. The -b option must be specified to enlarge
+ the size of the socket buffer and the -s option specifies the length
+ of the packet, which should be more than 65,535. For example,
+ type as follows:</para>
+
+ <para><userinput>
+ &prompt.user; <command>ping6 -b 70000 -s 68000 ::1</command>
+ </userinput></para>
+
+ <para>The IPv6 specification requires that the Jumbo Payload option
+ must not be used in a packet that carries a fragment header. If
+ this condition is broken, an ICMPv6 Parameter Problem message must
+ be sent to the sender. specification is followed, but you cannot
+ usually see an ICMPv6 error caused by this requirement.</para>
+
+ <para>When an IPv6 packet is received, the frame length is checked and
+ compared to the length specified in the payload length field of the
+ IPv6 header or in the value of the Jumbo Payload option, if any. If
+ the former is shorter than the latter, the packet is discarded and
+ statistics are incremented. You can see the statistics as output of
+ &man.netstat.8; command with `-s -p ip6' option:</para>
+
+ <screen>
+ &prompt.user; <command>netstat -s -p ip6</command>
+ ip6:
+ (snip)
+ 1 with data size < data length
+ </screen>
+
+ <para>So, kernel does not send an ICMPv6 error unless the erroneous
+ packet is an actual Jumbo Payload, that is, its packet size is more
+ than 65,535 bytes. As described above, currently no physical interface
+ with such a huge MTU is supported, so it rarely returns an
+ ICMPv6 error.</para>
+
+ <para>TCP/UDP over jumbogram is not supported at this moment. This
+ is because we have no medium (other than loopback) to test this.
+ Contact us if you need this.</para>
+
+ <para>IPsec does not work on jumbograms. This is due to some
+ specification twists in supporting AH with jumbograms (AH header
+ size influences payload length, and this makes it real hard to
+ authenticate inbound packet with jumbo payload option as well as AH).
+ </para>
+
+ <para>There are fundamental issues in *BSD support for jumbograms.
+ We would like to address those, but we need more time to finalize
+ these. To name a few:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>mbuf pkthdr.len field is typed as "int" in 4.4BSD, so
+ it will not hold jumbogram with len > 2G on 32bit architecture
+ CPUs. If we would like to support jumbogram properly, the field
+ must be expanded to hold 4G + IPv6 header + link-layer header.
+ Therefore, it must be expanded to at least int64_t
+ (u_int32_t is NOT enough).</para>
+ </listitem>
+
+ <listitem>
+ <para>We mistakingly use "int" to hold packet length in many
+ places. We need to convert them into larger integral type.
+ It needs a great care, as we may experience overflow during
+ packet length computation.</para>
+ </listitem>
+
+ <listitem>
+ <para>We mistakingly check for ip6_plen field of IPv6 header
+ for packet payload length in various places. We should be
+ checking mbuf pkthdr.len instead. ip6_input() will perform
+ sanity check on jumbo payload option on input, and we can
+ safely use mbuf pkthdr.len afterwards.</para>
+ </listitem>
+
+ <listitem>
+ <para>TCP code needs a careful update in bunch of places, of
+ course.</para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+
+ <sect3>
+ <title>Loop prevention in header processing</title>
+
+ <para>IPv6 specification allows arbitrary number of extension headers
+ to be placed onto packets. If we implement IPv6 packet processing
+ code in the way BSD IPv4 code is implemented, kernel stack may
+ overflow due to long function call chain. sys/netinet6 code
+ is carefully designed to avoid kernel stack overflow. Because of
+ this, sys/netinet6 code defines its own protocol switch
+ structure, as "struct ip6protosw" (see
+ <filename>netinet6/ip6protosw.h</filename>). There is no such
+ update to IPv4 part (sys/netinet) for compatibility, but small
+ change is added to its pr_input() prototype. So "struct ipprotosw"
+ is also defined. Because of this, if you receive IPsec-over-IPv4
+ packet with massive number of IPsec headers, kernel stack may blow
+ up. IPsec-over-IPv6 is okay. (Off-course, for those all IPsec
+ headers to be processed, each such IPsec header must pass each
+ IPsec check. So an anonymous attacker won't be able to do such an
+ attack.)</para>
+ </sect3>
+
+ <sect3 id="icmpv6">
+ <title>ICMPv6</title>
+
+ <para>After RFC2463 was published, IETF ipngwg has decided to
+ disallow ICMPv6 error packet against ICMPv6 redirect, to prevent
+ ICMPv6 storm on a network medium. This is already implemented
+ into the kernel.</para>
+ </sect3>
+
+ <sect3>
+ <title>Applications</title>
+
+ <para>For userland programming, we support IPv6 socket API as
+ specified in RFC2553, RFC2292 and upcoming internet drafts.</para>
+
+ <para>TCP/UDP over IPv6 is available and quite stable. You can
+ enjoy &man.telnet.1;, &man.ftp.1;, &man.rlogin.1;, &man.rsh.1;,
+ &man.ssh.1, etc. These applications are protocol independent.
+ That is, they automatically chooses IPv4 or IPv6 according to DNS.
+ </para>
+ </sect3>
+
+ <sect3>
+ <title>Kernel Internals</title>
+
+ <para>While ip_forward() calls ip_output(), ip6_forward() directly
+ calls if_output() since routers must not divide IPv6 packets into
+ fragments.</para>
+
+ <para>ICMPv6 should contain the original packet as long as possible
+ up to 1280. UDP6/IP6 port unreach, for instance, should contain
+ all extension headers and the *unchanged* UDP6 and IP6 headers.
+ So, all IP6 functions except TCP never convert network byte
+ order into host byte order, to save the original packet.</para>
+
+ <para>tcp_input(), udp6_input() and icmp6_input() can't assume that
+ IP6 header is preceding the transport headers due to extension
+ headers. So, in6_cksum() was implemented to handle packets whose IP6
+ header and transport header is not continuous. TCP/IP6 nor UDP6/IP6
+ header structure don't exist for checksum calculation.</para>
+
+ <para>To process IP6 header, extension headers and transport headers
+ easily, network drivers are now required to store packets in one
+ internal mbuf or one or more external mbufs. A typical old driver
+ prepares two internal mbufs for 96 - 204 bytes data, however, now
+ such packet data is stored in one external mbuf.</para>
+
+ <para><command>netstat -s -p ip6</command> tells you whether or not
+ your driver conforms such requirement. In the following example,
+ "cce0" violates the requirement. (For more information, refer to
+ Section 2.)</para>
+
+ <screen>
+ Mbuf statistics:
+ 317 one mbuf
+ two or more mbuf::
+ lo0 = 8
+ cce0 = 10
+ 3282 one ext mbuf
+ 0 two or more ext mbuf
+ </screen>
+
+ <para>Each input function calls IP6_EXTHDR_CHECK in the beginning to
+ check if the region between IP6 and its header is continuous.
+ IP6_EXTHDR_CHECK calls m_pullup() only if the mbuf has M_LOOP flag,
+ that is, the packet comes from the loopback interface. m_pullup()
+ is never called for packets coming from physical network interfaces.
+ </para>
+
+ <para>Both IP and IP6 reassemble functions never call m_pullup().</para>
+ </sect3>
+
+ <sect3 id="ipv6-wildcard-socket">
+ <title>IPv4 mapped address and IPv6 wildcard socket</title>
+
+ <para>RFC2553 describes IPv4 mapped address (3.7) and special behavior
+ of IPv6 wildcard bind socket (3.8). The spec allows you to:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Accept IPv4 connections by AF_INET6 wildcard bind
+ socket.</para>
+ </listitem>
+ <listitem>
+ <para>Transmit IPv4 packet over AF_INET6 socket by using
+ special form of the address like ::ffff:10.1.1.1.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>but the spec itself is very complicated and does not specify
+ how the socket layer should behave. Here we call the former one
+ "listening side" and the latter one "initiating side", for
+ reference purposes.</para>
+
+ <para>You can perform wildcard bind on both of the adderss families,
+ on the same port.</para>
+
+ <para>The following table show the behavior of FreeBSD 4.x.</para>
+
+ <screen>
+ listening side initiating side
+ (AF_INET6 wildcard (connetion to ::ffff:10.1.1.1)
+ socket gets IPv4 conn.)
+ --- ---
+FreeBSD 4.x configurable supported
+ default: enabled
+ </screen>
+
+ <para>The following sections will give you more details, and how you can
+ configure the behavior.</para>
+
+ <para>Comments on listening side:</para>
+
+ <para>It looks that RFC2553 talks too little on wildcard bind issue,
+ especially on the port space issue, failure mode and relationship
+ between AF_INET/INET6 wildcard bind. There can be several separate
+ interpretation for this RFC which conform to it but behaves differently.
+ So, to implement portable application you should assume nothing
+ about the behavior in the kernel. Using &man.getaddrinfo.3; is the
+ safest way. Port number space and wildcard bind issues were discussed
+ in detail on ipv6imp mailing list, in mid March 1999 and it looks
+ that there's no concrete consensus (means, up to implementers).
+ You may want to check the mailing list archives.</para>
+
+ <para>If a server application would like to accept IPv4 and IPv6
+ connections, there will be two alternatives.</para>
+
+ <para>One is using AF_INET and AF_INET6 socket (you'll need two
+ sockets). Use &man.getaddrinfo.3; with AI_PASSIVE into ai_flags,
+ and &man.socket.2; and &man.bind.2; to all the addresses returned.
+ By opening multiple sockets, you can accept connections onto the
+ socket with proper address family. IPv4 connections will be
+ accepted by AF_INET socket, and IPv6 connections will be accepted
+ by AF_INET6 socket.</para>
+
+ <para>Another way is using one AF_INET6 wildcard bind socket. Use
+ &man.getaddrinfo.3; with AI_PASSIVE into ai_flags and with
+ AF_INET6 into ai_family, and set the 1st argument hostname to
+ NULL. And &man.socket.2; and &man.bind.2; to the address returned.
+ (should be IPv6 unspecified addr). You can accept either of IPv4
+ and IPv6 packet via this one socket.</para>
+
+ <para>To support only IPv6 traffic on AF_INET6 wildcard binded socket
+ portably, always check the peer address when a connection is made
+ toward AF_INET6 listening socket. If the address is IPv4 mapped
+ address, you may want to reject the connection. You can check the
+ condition by using IN6_IS_ADDR_V4MAPPED() macro.</para>
+
+ <para>To resolve this issue more easily, there is system dependent
+ &man.setsockopt.2; option, IPV6_BINDV6ONLY, used like below.</para>
+
+ <screen>
+ int on;
+
+ setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char *)&on, sizeof (on)) < 0));
+ </screen>
+
+ <para>When this call succeed, then this socket only receive IPv6
+ packets.</para>
+
+ <para>Comments on initiating side:</para>
+
+ <para>Advise to application implementers: to implement a portable
+ IPv6 application (which works on multiple IPv6 kernels), we believe
+ that the following is the key to the success:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>NEVER hardcode AF_INET nor AF_INET6.</para>
+ </listitem>
+
+ <listitem>
+ <para>Use &man.getaddrinfo.3; and &man.getnameinfo.3;
+ throughout the system. Never use gethostby*(), getaddrby*(),
+ inet_*() or getipnodeby*(). (To update existing applications
+ to be IPv6 aware easily, sometime getipnodeby*() will be
+ useful. But if possible, try to rewrite the code to use
+ &man.getaddrinfo.3; and &man.getnameinfo.3;.)</para>
+ </listitem>
+
+ <listitem>
+ <para>If you would like to connect to destination, use
+ &man.getaddrinfo.3; and try all the destination returned,
+ like &man.telnet.1; does.</para>
+ </listitem>
+
+ <listitem>
+ <para>Some of the IPv6 stack is shipped with buggy
+ &man.getaddrinfo.3;. Ship a minimal working version with
+ your application and use that as last resort.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>If you would like to use AF_INET6 socket for both IPv4 and
+ IPv6 outgoing connection, you will need to use &man.getipnodebyname.3;.
+ When you would like to update your existing appication to be IPv6
+ aware with minimal effort, this approach might be choosed. But please
+ note that it is a temporal solution, because &man.getipnodebyname.3;
+ itself is not recommended as it does not handle scoped IPv6 addresses
+ at all. For IPv6 name resolution, &man.getaddrinfo.3; is the
+ preferred API. So you should rewrite your application to use
+ &man.getaddrinfo.3;, when you get the time to do it.</para>
+
+ <para>When writing applications that make outgoing connections,
+ story goes much simpler if you treat AF_INET and AF_INET6 as totally
+ seaprate address family. {set,get}sockopt issue goes simpler,
+ DNS issue will be made simpler. We do not recommend you to rely
+ upon IPv4 mapped address.</para>
+
+ <sect4>
+ <title>unified tcp and inpcb code</title>
+
+ <para>FreeBSD 4.x uses shared tcp code between IPv4 and IPv6
+ (from sys/netinet/tcp*) and separete udp4/6 code. It uses
+ unified inpcb structure.</para>
+
+ <para>The platform can be configured to support IPv4 mapped address.
+ Kernel configuration is summarized as follows:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>By default, AF_INET6 socket will grab IPv4
+ connections in certain condition, and can initiate
+ connection to IPv4 destination embedded in IPv4 mapped
+ IPv6 address.</para>
+ </listitem>
+
+ <listitem>
+ <para>You can disable it on entire system with sysctl like
+ below.</para>
+
+ <para>
+ <command>sysctl -w net.inet6.ip6.mapped_addr=0</command>
+ </para>
+
+ </listitem>
+ </itemizedlist>
+
+ <sect5>
+ <title>listening side</title>
+
+ <para>Each socket can be configured to support special AF_INET6
+ wildcard bind (enabled by default). You can disable it on
+ each socket basis with &man.setsockopt.2; like below.</para>
+
+ <screen>
+ int on;
+
+ setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char *)&on, sizeof (on)) < 0));
+ </screen>
+
+ <para>Wildcard AF_INET6 socket grabs IPv4 connection if and only
+ if the following conditions are satisfied:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>there's no AF_INET socket that matches the IPv4
+ connection</para>
+ </listitem>
+
+ <listitem>
+ <para>the AF_INET6 socket is configured to accept IPv4
+ traffic, i.e. getsockopt(IPV6_BINDV6ONLY) returns 0.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>There's no problem with open/close ordering.</para>
+ </sect5>
+
+ <sect5>
+ <title>initiating side</title>
+
+ <para>FreeBSD 4.x supports outgoing connetion to IPv4 mapped
+ address (::ffff:10.1.1.1), if the node is configured to support
+ IPv4 mapped address.</para>
+ </sect5>
+ </sect4>
+ </sect3>
+
+ <sect3>
+ <title>sockaddr_storage</title>
+
+ <para>When RFC2553 was about to be finalized, there was discusson on
+ how struct sockaddr_storage members are named. One proposal is to
+ prepend "__" to the members (like "__ss_len") as they should not be
+ touched. The other proposal was that don't prepend it (like "ss_len")
+ as we need to touch those members directly. There was no clear
+ consensus on it.</para>
+
+ <para>As a result, RFC2553 defines struct sockaddr_storage as
+ follows:</para>
+
+ <screen>
+ struct sockaddr_storage {
+ u_char __ss_len; /* address length */
+ u_char __ss_family; /* address family */
+ /* and bunch of padding */
+ };
+ </screen>
+
+ <para>On the contrary, XNET draft defines as follows:</para>
+
+ <screen>
+ struct sockaddr_storage {
+ u_char ss_len; /* address length */
+ u_char ss_family; /* address family */
+ /* and bunch of padding */
+ };
+ </screen>
+
+ <para>In December 1999, it was agreed that RFC2553bis should pick
+ the latter (XNET) definition.</para>
+
+ <para>Current implementation conforms to XNET definition, based on
+ RFC2553bis discusson.</para>
+
+ <para>If you look at multiple IPv6 implementations, you will be able
+ to see both definitions. As an userland programmer, the most
+ portable way of dealing with it is to:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>ensure ss_family and/or ss_len are available on the
+ platform, by using GNU autoconf,</para>
+ </listitem>
+
+ <listitem>
+ <para>have -Dss_family=__ss_family to unify all occurences
+ (including header file) into __ss_family, or</para>
+ </listitem>
+
+ <listitem>
+ <para>never touch __ss_family. cast to sockaddr * and use sa_family
+ like:</para>
+
+ <screen>
+ struct sockaddr_storage ss;
+ family = ((struct sockaddr *)&ss)->sa_family
+ </screen>
+
+ </listitem>
+ </orderedlist>
+ </sect3>
+ </sect2>
+
+ <sect2>
+ <title>Network Drivers</title>
+
+ <para>Now following two items are required to be supported by standard
+ drivers:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>mbuf clustering requirement. In this stable release, we
+ changed MINCLSIZE into MHLEN+1 for all the operating systems
+ in order to make all the drivers behave as we expect.</para>
+ </listitem>
+
+ <listitem>
+ <para>multicast. If &man.ifmcstat.8; yields no multicast group for
+ a interface, that interface has to be patched.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>If any of the driver don't support the requirements, then
+ the driver can't be used for IPv6 and/or IPsec communication. If
+ you find any problem with your card using IPv6/IPsec, then, please
+ report it to <email>freebsd-bugs@FreeBSD.org</email>.</para>
+
+ <para>(NOTE: In the past we required all pcmcia drivers to have a
+ call to in6_ifattach(). We have no such requirement any more)</para>
+ </sect2>
+
+ <sect2>
+ <title>Translator</title>
+
+ <para>We categorize IPv4/IPv6 translator into 4 types:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Translator A</emphasis> --- It is used in the early
+ stage of transition to make it possible to establish a
+ connection from an IPv6 host in an IPv6 island to an IPv4 host
+ in the IPv4 ocean.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Translator B</emphasis> --- It is used in the early
+ stage of transition to make it possible to establish a connection
+ from an IPv4 host in the IPv4 ocean to an IPv6 host in an
+ IPv6 island.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Translator C</emphasis> --- It is used in the late
+ stage of transition to make it possible to establish a
+ connection from an IPv4 host in an IPv4 island to an IPv6 host
+ in the IPv6 ocean.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Translator D</emphasis> --- It is used in the late
+ stage of transition to make it possible to establish a
+ connection from an IPv6 host in the IPv6 ocean to an IPv4 host
+ in an IPv4 island.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>TCP relay translator for category A is supported. This is called
+ "FAITH". We also provide IP header translator for category A.
+ (The latter is not yet put into FreeBSD 4.x yet.)</para>
+
+ <sect3>
+ <title>FAITH TCP relay translator</title>
+
+ <para>FAITH system uses TCP relay daemon called &man.faithd.8; helped
+ by the kernel. FAITH will reserve an IPv6 address prefix, and relay
+ TCP connection toward that prefix to IPv4 destination.</para>
+
+ <para>For example, if the reserved IPv6 prefix is
+ 3ffe:0501:0200:ffff::, and the IPv6 destination for TCP connection
+ is 3ffe:0501:0200:ffff::163.221.202.12, the connection will be
+ relayed toward IPv4 destination 163.221.202.12.</para>
+
+ <screen>
+ destination IPv4 node (163.221.202.12)
+ ^
+ | IPv4 tcp toward 163.221.202.12
+ FAITH-relay dual stack node
+ ^
+ | IPv6 TCP toward 3ffe:0501:0200:ffff::163.221.202.12
+ source IPv6 node
+ </screen>
+
+ <para>&man.faithd.8; must be invoked on FAITH-relay dual stack
+ node.</para>
+
+ <para>For more details, consult
+ <filename>src/usr.sbin/faithd/README</filename></para>
+ </sect3>
+ </sect2>
+
+ <sect2 id="ipsec-implementation">
+ <title>IPsec</title>
+
+ <para>IPsec is mainly organized by three components.</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Policy Management</para>
+ </listitem>
+
+ <listitem>
+ <para>Key Management</para>
+ </listitem>
+
+ <listitem>
+ <para>AH and ESP handling</para>
+ </listitem>
+ </orderedlist>
+
+ <sect3>
+ <title>Policy Management</title>
+
+ <para>The kernel implements experimental policy management code.
+ There are two way to manage security policy. One is to configure
+ per-socket policy using &man.setsockopt.2;. In this cases, policy
+ configuration is described in &man.ipsec.set.policy.3;. The other
+ is to configure kernel packet filter-based policy using PF_KEY
+ interface, via &man.setkey.8;.</para>
+
+ <para>The policy entry is not re-ordered with its
+ indexes, so the order of entry when you add is very significant.</para>
+ </sect3>
+
+ <sect3>
+ <title>Key Management</title>
+
+ <para>The key management code implemented in this kit (sys/netkey)
+ is a home-brew PFKEY v2 implementation. This conforms to RFC2367.
+ </para>
+
+ <para>The home-brew IKE daemon, "racoon" is included in the
+ kit (kame/kame/racoon). Basically you'll need to run racoon as
+ daemon, then setup a policy to require keys (like
+ <command>ping -P 'out ipsec esp/transport//use'</command>).
+ The kernel will contact racoon daemon as necessary to exchange
+ keys.</para>
+ </sect3>
+
+ <sect3>
+ <title>AH and ESP handling</title>
+
+ <para>IPsec module is implemented as "hooks" to the standard IPv4/IPv6
+ processing. When sending a packet, ip{,6}_output() checks if ESP/AH
+ processing is required by checking if a matching SPD (Security
+ Policy Database) is found. If ESP/AH is needed,
+ {esp,ah}{4,6}_output() will be called and mbuf will be updated
+ accordingly. When a packet is received, {esp,ah}4_input() will be
+ called based on protocol number, i.e. (*inetsw[proto])().
+ {esp,ah}4_input() will decrypt/check authenticity of the packet,
+ and strips off daisy-chained header and padding for ESP/AH. It is
+ safe to strip off the ESP/AH header on packet reception, since we
+ will never use the received packet in "as is" form.</para>
+
+ <para>By using ESP/AH, TCP4/6 effective data segment size will be
+ affected by extra daisy-chained headers inserted by ESP/AH. Our
+ code takes care of the case.</para>
+
+ <para>Basic crypto functions can be found in directory "sys/crypto".
+ ESP/AH transform are listed in {esp,ah}_core.c with wrapper functions.
+ If you wish to add some algorithm, add wrapper function in
+ {esp,ah}_core.c, and add your crypto algorithm code into
+ sys/crypto.</para>
+
+ <para>Tunnel mode is partially supported in this release, with the
+ following restrictions:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>IPsec tunnel is not combined with GIF generic tunneling
+ interface. It needs a great care because we may create an
+ infinite loop between ip_output() and tunnelifp->if_output().
+ Opinion varies if it is better to unify them, or not.</para>
+ </listitem>
+
+ <listitem>
+ <para>MTU and Don't Fragment bit (IPv4) considerations need more
+ checking, but basically works fine.</para>
+ </listitem>
+
+ <listitem>
+ <para>Authentication model for AH tunnel must be revisited.
+ We'll need to improve the policy management engine,
+ eventually.</para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+
+ <sect3>
+ <title>Conformance to RFCs and IDs</title>
+
+ <para>The IPsec code in the kernel conforms (or, tries to conform)
+ to the following standards:</para>
+
+ <para>"old IPsec" specification documented in
+ <filename>rfc182[5-9].txt</filename></para>
+
+ <para>"new IPsec" specification documented in
+ <filename>rfc240[1-6].txt</filename>,
+ <filename>rfc241[01].txt</filename>, <filename>rfc2451.txt</filename>
+ and <filename>draft-mcdonald-simple-ipsec-api-01.txt</filename>
+ (draft expired, but you can take from <ulink
+ url="ftp://ftp.kame.net/pub/internet-drafts/">
+ ftp://ftp.kame.net/pub/internet-drafts/</ulink>).
+ (NOTE: IKE specifications, <filename>rfc241[7-9].txt</filename> are
+ implemented in userland, as "racoon" IKE daemon)</para>
+
+ <para>Currently supported algorithms are:</para>
+ <itemizedlist>
+ <listitem>
+ <para>old IPsec AH</para>
+ <itemizedlist>
+ <listitem>
+ <para>null crypto checksum (no document, just for
+ debugging)</para>
+ </listitem>
+ <listitem>
+ <para>keyed MD5 with 128bit crypto checksum
+ (<filename>rfc1828.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>keyed SHA1 with 128bit crypto checksum
+ (no document)</para>
+ </listitem>
+ <listitem>
+ <para>HMAC MD5 with 128bit crypto checksum
+ (<filename>rfc2085.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>HMAC SHA1 with 128bit crypto checksum
+ (no document)</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>old IPsec ESP</para>
+ <itemizedlist>
+ <listitem>
+ <para>null encryption (no document, similar to
+ <filename>rfc2410.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>DES-CBC mode (<filename>rfc1829.txt</filename>)</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>new IPsec AH</para>
+ <itemizedlist>
+ <listitem>
+ <para>null crypto checksum (no document,
+ just for debugging)</para>
+ </listitem>
+ <listitem>
+ <para>keyed MD5 with 96bit crypto checksum
+ (no document)</para>
+ </listitem>
+ <listitem>
+ <para>keyed SHA1 with 96bit crypto checksum
+ (no document)</para>
+ </listitem>
+ <listitem>
+ <para>HMAC MD5 with 96bit crypto checksum
+ (<filename>rfc2403.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>HMAC SHA1 with 96bit crypto checksum
+ (<filename>rfc2404.txt</filename>)</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>new IPsec ESP</para>
+ <itemizedlist>
+ <listitem>
+ <para>null encryption
+ (<filename>rfc2410.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>DES-CBC with derived IV
+ (<filename>draft-ietf-ipsec-ciph-des-derived-01.txt</filename>,
+ draft expired)</para>
+ </listitem>
+ <listitem>
+ <para>DES-CBC with explicit IV
+ (<filename>rfc2405.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>3DES-CBC with explicit IV
+ (<filename>rfc2451.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>BLOWFISH CBC
+ (<filename>rfc2451.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>CAST128 CBC
+ (<filename>rfc2451.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>RC5 CBC
+ (<filename>rfc2451.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>each of the above can be combined with:</para>
+ <itemizedlist>
+ <listitem>
+ <para>ESP authentication with HMAC-MD5(96bit)</para>
+ </listitem>
+ <listitem>
+ <para>ESP authentication with HMAC-SHA1(96bit)</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+
+ <para>The following algorithms are NOT supported:</para>
+ <itemizedlist>
+ <listitem>
+
+ <para>old IPsec AH</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>HMAC MD5 with 128bit crypto checksum + 64bit
+ replay prevention (<filename>rfc2085.txt</filename>)</para>
+ </listitem>
+ <listitem>
+ <para>keyed SHA1 with 160bit crypto checksum + 32bit padding
+ (<filename>rfc1852.txt</filename>)</para>
+ </listitem>
+ </itemizedlist>
+
+ </listitem>
+ </itemizedlist>
+
+ <para>IPsec (in kernel) and IKE (in userland as "racoon") has been
+ tested at several interoperability test events, and it is known to
+ interoperate with many other implementations well. Also, current
+ IPsec implementation as quite wide coverage for IPsec crypto
+ algorithms documented in RFC (we cover algorithms without intellectual
+ property issues only).</para>
+ </sect3>
+
+ <sect3 id="ipsec-ecn">
+ <title>ECN consideration on IPsec tunnels</title>
+
+ <para>ECN-friendly IPsec tunnel is supported as described in
+ <filename>draft-ipsec-ecn-00.txt</filename>.</para>
+
+ <para>Normal IPsec tunnel is described in RFC2401. On encapsulation,
+ IPv4 TOS field (or, IPv6 traffic class field) will be copied from inner
+ IP header to outer IP header. On decapsulation outer IP header
+ will be simply dropped. The decapsulation rule is not compatible
+ with ECN, since ECN bit on the outer IP TOS/traffic class field will be
+ lost.</para>
+
+ <para>To make IPsec tunnel ECN-friendly, we should modify encapsulation
+ and decapsulation procedure. This is described in <ulink
+ url="http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt">
+ http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt</ulink>,
+ chapter 3.</para>
+
+ <para>IPsec tunnel implementation can give you three behaviors, by
+ setting net.inet.ipsec.ecn (or net.inet6.ipsec6.ecn) to some
+ value:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>RFC2401: no consideration for ECN (sysctl value -1)</para>
+ </listitem>
+ <listitem>
+ <para>ECN forbidden (sysctl value 0)</para>
+ </listitem>
+ <listitem>
+ <para>ECN allowed (sysctl value 1)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Note that the behavior is configurable in per-node manner,
+ not per-SA manner (draft-ipsec-ecn-00 wants per-SA configuration,
+ but it looks too much for me).</para>
+
+ <para>The behavior is summarized as follows (see source code for
+ more detail):</para>
+
+ <screen>
+
+ encapsulate decapsulate
+ --- ---
+RFC2401 copy all TOS bits drop TOS bits on outer
+ from inner to outer. (use inner TOS bits as is)
+
+ECN forbidden copy TOS bits except for ECN drop TOS bits on outer
+ (masked with 0xfc) from inner (use inner TOS bits as is)
+ to outer. set ECN bits to 0.
+
+ECN allowed copy TOS bits except for ECN use inner TOS bits with some
+ CE (masked with 0xfe) from change. if outer ECN CE bit
+ inner to outer. is 1, enable ECN CE bit on
+ set ECN CE bit to 0. the inner.
+
+ </screen>
+
+ <para>General strategy for configuration is as follows:</para>
+ <itemizedlist>
+ <listitem>
+ <para>if both IPsec tunnel endpoint are capable of ECN-friendly
+ behavior, you'd better configure both end to "ECN allowed"
+ (sysctl value 1).</para>
+ </listitem>
+ <listitem>
+ <para>if the other end is very strict about TOS bit, use "RFC2401"
+ (sysctl value -1).</para>
+ </listitem>
+ <listitem>
+ <para>in other cases, use "ECN forbidden" (sysctl value 0).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The default behavior is "ECN forbidden" (sysctl value 0).</para>
+
+ <para>For more information, please refer to:</para>
+
+ <para><ulink
+ url="http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt">
+ http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt</ulink>,
+ RFC2481 (Explicit Congestion Notification),
+ src/sys/netinet6/{ah,esp}_input.c</para>
+
+ <para>(Thanks goes to Kenjiro Cho <email>kjc@csl.sony.co.jp</email>
+ for detailed analysis)</para>
+ </sect3>
+
+ <sect3>
+ <title>Interoperability</title>
+
+ <para>Here are (some of) platforms that KAME code have tested
+ IPsec/IKE interoperability in the past. Note that both ends may
+ have modified their implementation, so use the following list just
+ for reference purposes.</para>
+
+ <para>Altiga, Ashley-laurent (vpcom.com), Data Fellows (F-Secure),
+ Ericsson ACC, FreeS/WAN, HITACHI, IBM AIX, IIJ, Intel,
+ Microsoft WinNT, NIST (linux IPsec + plutoplus), Netscreen, OpenBSD,
+ RedCreek, Routerware, SSH, Secure Computing, Soliton, Toshiba,
+ VPNet, Yamaha RT100i</para>
+ </sect3>
+ </sect2>
+ </sect1>
</chapter>
<!--
Local Variables:
mode: sgml
sgml-declaration: "../chapter.decl"
sgml-indent-data: t
sgml-omittag: nil
sgml-always-quote-attributes: t
sgml-parent-document: ("../book.sgml" "part" "chapter")
End:
-->
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Feb 21, 9:07 PM (10 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16745013
Default Alt Text
(132 KB)
Attached To
Mode
R9 FreeBSD doc repository
Attached
Detach File
Event Timeline
Log In to Comment