Overview
========

This is a repo of just the modified bits of a uClinux tree needed to
get libreswan building.

To make it usable go to lantronix and get their linux SDK and layer
this on top of that.

For building instructions see the next session.

For what's left see: TODO.

For how to hack in this git repo see: Hacking

For a summary of issues addressed see: What was "fixed".


Setting up the VM to build Libreswan (IPSEC) for Lantronix XPort Pro (m68k)
===========================================================================


These notes are based on the official SDK (version 2.0.0.3) included
in the VMware image provided by Lantronix.


Download and set up the VM 
--------------------------

The lantronix SDK image is based on Ubuntu 10.04 (lucid); upstream was
Debian/Squeeze.  It can be found at:

  ftp://ftp.lantronix.com/pub/Linux_SDK/SDK2_0_0_3/linux_sdk_2_0_0_3_VMware_Install.zip

First download and set up this VM using VMware.  To login, the account
is:

  Username: lantronix
  Password: PASS

### Using KVM?

While VMware is recommended; it is possible to convert the image to
KVM using:

* unpacking the zip file using: unzip SDK2_0_0_3/linux_sdk_2_0_0_3_VMware_Install.zip
* convert the disk files to qcow2 using: qemu-img convert -O qcow2 linux_sdk_2_0_0_3_VMware_Install/*.vmdk lantronix.qcow2
* creating a VM with Linux / Debian Squeeze as the OS type


Customize/fix the VM
--------------------

In part because the VM based on a very old release a number of changes
need to be made before things work.


* eliminate the need to specify the SUDO password

  Using visudo (sudo visudo), append this line to the very end of the
  /etc/sudoers file:

    lantronix ALL=(ALL) NOPASSWD: ALL

  Verify this step by opening a new terminal and then running:

    $ sudo pwd

  it should not prompt for the password.
  

* fix the repository list

  Because the deb repositories used by this release have been moved to
  old-releases.ubuntu.com the file /etc/apt/sources.list needs to be
  updated.  Without this, attempts to install additional packages will
  fail.

    $ sudo cp /etc/apt/sources.list /etc/apt/sources.bak
    $ sudo sed -i -e 's/security.ubuntu.com/old-releases.ubuntu.com/' /etc/apt/sources.list
    $ sudo sed -i -e 's/us.archive.ubuntu.com/old-releases.ubuntu.com/' /etc/apt/sources.list

  Verify this step by running:

    $ sudo apt-get update

  it should get no errors.


In addition, consider:

* enabling autologin (and turning off the login sound):

  System -> Administration -> Login Screen

* diabling the screen saver:

  System -> Preferences -> Screen Saver

* installing and enabling openssh-server so remote logins are possible

  sudo apt-get install ssh

* shutdown when VM's "power button" is pressed:

  System -> Preferences -> Power Management : General


Install missing packages
------------------------

Required by the updated compiler:

  $ sudo apt-get install libmpc2

Required when building NSS:

  $ sudo apt-get install autoconf


Install a more up-to-date compiler
----------------------------------

The compiler supplied by lantronix is not able to handle the large
libreswan image.  Specifically, the default 64k GOT (global offset
table) overflows and the standard workaround (compile with -mxgot)
doesn't work (elf2flt doesn't handle the 32-bit relocations that
-mxgot creates).

To get around this, download and install a more recent compiler from:

  http://www.uclinux.org/pub/uClinux/m68k-elf-tools/

for instance:

  $ wget http://www.uclinux.org/pub/uClinux/m68k-elf-tools/tools-20101118/m68k-uclinux-tools-20101118.sh
  $ sudo sh ./m68k-uclinux-tools-20101118.sh

Check the compiler by running:

  /usr/local/libexec/gcc/m68k-uclinux/4.5.1/cc1

If it gets an error like:

  $ /usr/local/libexec/gcc/m68k-uclinux/4.5.1/cc1 --help
  /usr/local/libexec/gcc/m68k-uclinux/4.5.1/cc1: error while loading shared libraries: libmpc.so.2: cannot open shared object file: No such file or directory

then, most likely, libmpc2 was not installed.  See above.


Create a copy of the source tree with changes applied
-----------------------------------------------------

The changes to lantronix for libreswan can be found in:

  http://download.libreswan.org/lantronix

while the original sources are found in ~/linuxsdk.  Make a copy of
the original sources and overlay the libreswan changes.  For instance,
using the tar ball:

  http://download.libreswan.org/lantronix/libreswan-sdk-20151115.tar.gz

then:

  $ wget http://download.libreswan.org/lantronix/libreswan-sdk-20151115.tar.gz
  $ cp -r linuxsdk libreswan-sdk-20151115
  $ gunzip < libreswan-sdk-20151115.tar.gz | tar xpf -
  $ mv libreswan-sdk-20151115 lsw-linuxsdk


Pre-download some sources
-------------------------

Since the above sources were released the location of several of the
source tar balls has changed.  To get around this:

* Mozilla moved the location of NSS.  Run this:

  $ mkdir -p ~/.downloads
  $ ( cd ~/.downloads && wget http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_17_4_RTM/src/nss-3.17.4-with-nspr-4.10.7.tar.gz )

* The shipped wget doesn't correctly handle libreswan's certificate.
  Run this (or install/use "curl"):

  $ mkdir -p ~/.downloads
  $ (cd ~/.downloads && wget --no-check-certificate "https://download.libreswan.org/libreswan-3.12.tar.gz")



Building libreswan for XPort Pro
================================


1. set up your environment

     $ cd ~/lsw-linuxsdk
     $ . ./env_m68k-uclinux

   and check you're picking up the newer m68k compiler

     $ which m68k-uclinux-gcc
     /usr/local/bin/m68k-uclinux-gcc

   Note: the top-level Makefile also does this automatically.


2. configure for a Lantronix LIBRESWAN build:

   Start the menu configuration tool:

     $ make menuconfig

   From the main "uClinux Distribution Configuration" screen, go into
   the Vendor/Product selection and ensure that the LIBRESWAN
   configuration is selected:
      
      --- Select the Vendor you wish to target
         Vendor (Lantronix)  --->
      --- Select the Product you wish to target
         Lantronix Products (XPort_Pro_16MB)  --->
         Configuration Profile (LIBRESWAN)  --->

3. build the image

     $ make

   the result:

     linux/images/image.bin

   contains both the kernel and the ROMFS.

   If the image is too big, the kernel will abort during boot.  The
   parameter:

     KERNEL_END_ADDR

   found in:

     linux/linux-2.6.x/drivers/mtd/maps/m520x.c

   can be adjusted as required.


Installing libreswan on XPort Pro
=================================

#. configure the board to boot/run from flash:

      dBUG> set autoboot flash
      dBUG> set kcl rootfstype=romfs
      dBUG> set romfs_flash on
      dBUG> set bootbank 1

   In addition, if the following parameters are set:

      dBUG> set client N.N.N.N
      dBUG> set netmask 255.255.255.0
      dBUG> set dns N.N.N.N
      dBUG> set gateway N.N.N.N

   then, during the boot, /etc/netcfg will try to configure the
   default interface using their values (this avoids the need to use
   dhcpc).


#. flash the kernel+romfs

   On the build system:

      $ cp linux/images/image.bin /tftpboot

   On the target board:

      dBUG> dnfl image.bin


#. flash an empty file system in the "UserSpace"

   XXX: For some reason, not having this leads to the init scripts
   killing "init" which, in turn, causes the kernel to panic.

   For instance, the below creates a 786432-byte JFFS and writes it to
   0x740000 in the flash (the default LIBRESWAN kernel, when built
   with boot-banks, expects a JFFS at that address):

   $ . ./env<tab>
   $ rm -rf empty
   $ mkdir empty
   $ # source dest size flash-block-size
   $ mkjffs2.sh empty /tftpboot/empty.jffs 0xc0000 0x20000

   dBUG> dn empty.jffs
   Address:  0x4001FF80
   Downloading Image 'empty.jffs' from 192.168.16.100
   TFTP transfer completed 
   Read 786432 bytes (1537 blocks)
   dBUG> fl w 0x740000 0x4001FF80 0xc0000
   ......
   Flash Write complete. 0xC0000 bytes written


Network Configuration
=====================

The startup script:

   linux/user/libreswan/config/etc/netcfg

which is installed, on the ROMFS, as:

   /etc/netcfg

(and sourced by /etc/netstart) uses the network configuration settings
in the ROM:

      server: 192.168.16.100
      client: 192.168.16.101
     gateway: 192.168.16.1
     netmask: 255.255.255.0
         dns: 192.168.16.1

to configure eth0.  During boot, a message like:

   netcfg: IPADDR=192.168.16.101 NETMASK=255.255.255.0 GATEWAY=192.168.16.1 DNS=192.168.16.1

will be displayed

Note: the combination of DHCP and libreswan has not been tested.


Libreswan Configuration
=======================

To automate the starting of libreswan during boot the following
configuration files and directories are required:

   /etc/ipsec.conf    -> /var/etc/ipsec.conf
   /etc/ipsec.secrets -> /var/etc/ipsec.secrets
   /etc/ipsec.d/      -> /var/etc/ipsec.d/

The startup script:

   linux/user/libreswan/config/etc/rcS.d/S14libreswan

which is installed, on the ROMFS, as:

   /etc/rcS.d/S14libreswan

will search for existing or pre-loaded configuration files and link
those to the above.  The exact search sequence is described further
down.

If /etc/ipsec.d/ does not exist, or does not appear to contain a
certificate database, then S14libreswan will create that directory and
initialize the database.

If files matching /etc/ipsec.d/$NAME.p12.$PASSWORD exist, then
S14libreswan will attempt to load those PKCS12 files into the
certificate database using $PASSWORD as the certificate password.

If the file /etc/ipsec.d/pluto.sh exists then, instead of starting
pluto (ipsec) using "pluto &", S14libreswan will invoke that script.

If the time is invalid (that is, before 2015), then (as a workaround
for boards that do not have a clock) S14libreswan will use the "Not
Before" time obtained from any /etc/ipsec.d/$NAME.p12.$PASSWORD as the
current time.

Below are detailed the locations that S14libreswan will look for
configuration files.

Permenant Storage on a JFFS in "UserSpace" Partition
----------------------------------------------------

This option is best suited for interactive deployments where the
configuration is expected to change at runtime; say using a web
interface.

If there is a JFFS file system in the "UserSpace" partition with a
top-level etc/ directory containing ipsec.* files and directories then
that will be used for libreswan's configuration.

For instance, if you wish to make the current ipsec configuration
permenant then use:

   # cp -r /var/etc/ipsec.* /usr/local/etc
   # rm /usr/local/etc/ipsec.d/*.p12.*
   # reboot

During boot, expect messages like:

   S14libreswan: /etc/ipsec.conf linked to /var/etc/ipsec.conf linked to /usr/local/etc/ipsec.conf

Ways to populate the /usr/local/etc/ directory include: manually (as
above); pre-populated as part of the JFFS written to the "UserSpace"
partition; or a custom script that also updates /var/etc's links and
re-initializes pluto.

Tar Archive in "UserExtra" Partition
------------------------------------

This option is best suited for more automated deployments where the
configuration is expected to be downloaded and flashed before boot.

If the "UserExtra" partition contains what looks like a tar archive
then any configuration files etc/ipsec.* and not yet located will be
unpacked into /var/etc (a TMPFS).

For instance, using libreswan's default configuration as a starting
point:

- create an x509 configuration that will auto-start on boot:

   $ rm -rf etc
   $ mkdir etc
   $ cp -rv linux/user/libreswan/config/etc/ipsec.* etc
   `linux/user/libreswan/config/etc/ipsec.conf' -> `etc/ipsec.conf'
   `linux/user/libreswan/config/etc/ipsec.d' -> `etc/ipsec.d'
   `linux/user/libreswan/config/etc/ipsec.d/updown.sh' -> `etc/ipsec.d/updown.sh'
   `linux/user/libreswan/config/etc/ipsec.secrets' -> `etc/ipsec.secrets'
   $ sed -i -e 's/#x509:auto=start/auto=start/' etc/ipsec.conf

- add certificates to import into the certificate database to the
  etc/ipsec.d/ directory (the certificate "east.12.foobar", for
  instance, has "foobar" as its password):

   $ cp ../east.p12 etc/ipsec.d/east.p12.foobar
   $ cp ../west.p12 etc/ipsec.d/west.p12.foobar

- bundle the configuration into a tar archive:

   $ tar cvf /tftpboot/etc.tar etc
   etc/
   etc/ipsec.conf
   etc/ipsec.secrets
   etc/ipsec.d/
   etc/ipsec.d/west.p12.foobar
   etc/ipsec.d/east.p12.foobar
   etc/ipsec.d/updown.sh

- determinte the size, in HEX, of the archive (needed below):

   $ printf '0x%x\n' $(wc -c < /tftpboot/etc.tar)
   0x5000

- flash the archive to the UserExtra partition:

   dBUG> dn etc.tar
   Address:  0x4001FF80
   Downloading Image 'etc.tar' from 192.168.16.100
   TFTP transfer completed 
   Read 20480 bytes (41 blocks)
   dBUG> fl w 0x800000 0x4001FF80 0x5000
   Must erase complete sectors (0x00800000 to 0x0081FFFF)
   Continue (yes | no)? yes
   .
   Flash Write complete. 0x5000 bytes written

During boot, expect messages like:

   S14libreswan: /etc/ipsec.conf linked to /var/etc/ipsec.conf extracted from UserExtra
   ...
   S14libreswan: Adding /etc/ipsec.d/east.p12.foobar to /etc/ipsec.d
   pk12util: PKCS12 IMPORT SUCCESSFUL
   ...


In ROMFS under /etc/default.ipsec
---------------------------------

This option is best suited as a way to kick-start a deployment being
debugged.

The directory:

   linux/user/libreswan/config/etc/

contains default configuration files for libreswan.  In the root
ROMFS, they are found under /etc/default.ipsec/.  If no other
configuration file or directory has been found, then S14libreswan will
copy them to /var/etc (a TMPFS).

By modifying those files and building a new root file system, a
different default configuration can be created.

During boot, expect messages like:

   S14libreswan: /etc/ipsec.conf linked to /var/etc/ipsec.conf copied from /etc/default.ipsec/ipsec.conf

(Note: /etc/default/ isn't used as that is not geared to installing
both files and directories)


Example Configurations
======================

Found in linux/user/libreswan/config/etc are a set of configuration
files that are flashed by default.  The're sufficent to demonstrate a
pre-shared-key (PSK) IPSEC connection.  With addition of PKCS12
certificates named "east" and "west" they can also be used to
demonstrate a X509 authenticated IPSEC connections.

PSK
---

See the file ipsec-psk-linuxsdk.sh for how to configure the server,
and the file ipsec-psk-lantronix.sh for how to start the client.


x509
----

See the file ipsec-x509-linuxsdk.sh for how to configure the server.
and the file ipsec-x509-lantronix.sh for how to start the client.

You'll need to supply certificate files.


TODO
====

If "UserSpace" does not contain a JFFS file system, the kernel will
panic because init gets killed.  Presumably by one of the init
scripts.  Work around is to ensure that "UserSpace" does contain a
valid file system.

Really confirm that the huge, but commented out, function found in
SQLITE is actually used by NSS.  So far it seems ok.

Correctly install the NSS libraries into the build environment.
Requires changes to linux/lib/Makefile? so that they get copied to the
correct location.  This will let us simplify the pluto link line.

Cleanup libreswan's include and library paths.  Needs NSS libraries to
be installed correctly.

Update NSS to current?

Update libreswan to current?  This may require an update to NSS; and
will require an import of libevent.

Set up libreswan's "make menuconfig" to be more like "openswan".  That
is, with the ability to select the programs that are built and
installed.

Set up NSS's "make menuconfig" to be more like "openswan".  That is,
with the ability to select the programs that are built and installed.

Get more of the NSS binaries running; some just required libz.  Since
the needed commands "certutil" and "pk12util" build this isn't
critical.


What was "fixed"
================

For reference, this section notes each of the problems encountered.
If you're looking to forward port then this list of issues might be a
good start.

Kernel 2.6
----------

#. Needed to enable ROMFS_BACKED_BY_MTD so that it would run directly
   from the ROM.

#. Needed to hack the MTD chip driver so that it will allow running
   code from rom

#. Needed to hack the ROMFS partition map to support, and validate, a
   Kernel partition (contains kernel and ROMFS) > 4MB (but less then
   8MB).

uClibc
------

Userland
--------

#. "date -s ..." didn't work because mktime(3) was being mis-compiled

#. /bin/sh only allowed 1k(?) command lines by default, increased to
   4k(?) so that long shell command lines (for instance updown invoked
   by pluto), worked.

NSS+NSPR
--------

#. Need to build NSS statically

   Mozilla bugs 533014 and 534471 contain patches to help with this.
   They have been partially merged.

   For instance: the patches namespace proof some common function
   names and that has been applied; where as the attempt to avoid -ldl
   and dl*() calls is less complete.

#. NSPR's configure.in has autoconf 2.13 problems

   After autoconf 2.13, the use of target, host, and build changed and
   NSPR's configure.in has never really been properly updated.

   For instance: tests for "$target" != "$host" (should instead check
   "$build"); the compiler variable names like HOST_CC are
   out-of-date.

#. NSS/NSPR think they know the correct compiler flags

   For instance, forcing -m68020-60 and -O and -fPIC.

#. uClinux Makefile's "export all" interacts badly with NSS+NSPR

   For instance, instead of using local DIR it uses one defined higher
   up.  May need to add lots of unexport lines.

#. fork() calls

   For instance, nss/lib/freebl/unix_rand.c

#. very large functions

   For instance, nss/lib/sqlite/sqlite3.c:sqlite3VdbeExec, which was
   simply commented out.

#. linux audit assumed when LINUX

   For instance, nss/lib/softoken/fipstokn.c

Libreswan
---------

#. stuff needed to be disabled, for instance ADNS

#. fork assumed, even when use-vfork

#. need to hardwire the link line to link against NSS

#. klips isn't fully disable when disabled

#. the existing updown scripts, which use shell "functions", just
   won't work


Hacking
=======


Modifying uClinux
-----------------

First, you'll likely want to set the following GIT options:

    git config status.showUntrackedFiles no

which will stop git complaining about the files not yet in the
repository.

If you need to modify a file that is part of the uCLinux distro:

#. if not already, add it, unmodified to the GIT repo; use the commit
   message "import"

#. modify the file

#. commit the changes

If you need to patch either NSS or libreswan source FILE, then you'll
need to add a "z" series patch to {lib/nss,user/libreswan}/patches:

#. go to the relevant build directory:

      cd linux/lib/nss/build

   or:

      cd linux/user/libreswan/build

#. save a copy of the original file

      cp ${FILE}{,.LSW}

#. edit ${FILE}

#. create a patch and save it in ../patches; all the local patches are
   ordered as z01, z02, ...

      diff -u ${FILE}{.LSW,} > ../patches/<tab>-zNN-......patch


Hacking S14libreswan et.al.
---------------------------

#. build/flash the default configuration

#. copy /var/etc/ipsec.* to /usr/local/etc/

#. copy /etc/rcS.d/S14libreswan to /usr/local/etc/rcS.d/S14libreswan

On boot, /etc/rcS.d/S14libreswan will then invoke and use
/usr/local/etc/.


Network booting and NFS
-----------------------

Be warned, NFS can't use XIP so running commands tends to be a
one-shot.  This is best suited for debugging the kernel or a specific
application.

On the board, check that the following are valid:

      server: 192.168.16.100
      client: 192.168.16.101
     netmask: 255.255.255.0
    filename: linux.bin
    filetype: Image
    autoboot: net

to still use the ROMFS set:

   dBUG> set kcl rootfstype=romfs

or to use a NFS file system:

   dBUG> set kcl noinitrd rw root=/dev/nfs \
      ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf> \
      nfsroot=<server-ip>:/home/lantronix/linuxsdk/linux/nfs

for instance:

   dBUG> set kcl noinitrd rw root=/dev/nfs \
      ip=192.168.16.101:192.168.16.100::255.255.255.0::eth0: \
      nfsroot=192.168.16.100:/home/lantronix/linuxsdk/linux/nfs

See the uClinux documentation for the config parameters in the kernel
that need tweeking.  Hint:

> CONFIG_NETWORK_FILESYSTEMS=y
> CONFIG_NFS_FS=y
> CONFIG_NFS_V3=y
> CONFIG_ROOT_NFS=y

Mounting NFS file systems
-------------------------

The two critical things are:

- add portmap to userland

- start portmap in the background before attempting an NFS mount

As for configuration options, the below are probably overkill:

- kernel

> CONFIG_NETWORK_FILESYSTEMS=y
> CONFIG_NFS_FS=y
> CONFIG_NFS_V3=y
> CONFIG_ROOT_NFS=y

> CONFIG_LOCKD=y
> CONFIG_LOCKD_V4=y
> CONFIG_NFS_COMMON=y
> CONFIG_SUNRPC=y

- userland

> CONFIG_USER_PORTMAP_PORTMAP=y
> # CONFIG_USER_PORTMAP_PMAP_SET is not set
> # CONFIG_USER_PORTMAP_PMAP_DUMP is not set
> CONFIG_USER_BUSYBOX_FEATURE_HAVE_RPC=y
> CONFIG_USER_BUSYBOX_FEATURE_MOUNT_NFS=y

> CONFIG_USER_BUSYBOX_INETD=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y
> CONFIG_USER_BUSYBOX_FEATURE_INETD_RPC=y
