Skip to content

TLVC Networking Guide

Helge Skrivervik edited this page Jan 1, 2024 · 8 revisions

Intro

TLVC inherited a relatively complete and reliable networking platform from ELKS: A reliable TCP/IP network stack and drivers to support the 10Mbps Ethernet and serial network connections (SLIP) networks. Since the fork, ktcp – the TCP/IP protocol engine – and the underlying drivers have been enhanced with stability and speed improvements and some bug fixes.

At the application level, TLVC supports the telnet-protocol (inbound and outbound) for interactive access, the ftp-protocol (inbound and outbound) for file transfers and http via the TLVC httpd server. The ftp/ftpd client/server pair have been written from scratch for ELKS/TLVC and include special functionality to accommodate a QEMU setting (see below).

In addition to this document, there are many details to be found in the man-pages, like man ktcp or man ne - the latter for info about the NE1k/NE2k Ethernet drivers.

TLVC Networking Support

TLVC supports several different ISA-based Ethernet interfaces and a solid TCP/IP implementation via the ktcp user space process. The quality and diversity of this support is improving constantly. Until (approximately) 2020 the urlget program was the key to move files into TLVC. Today, the ftp user application and the ftpd server deamon - which implement most basic ftp commands, represent the most convenient file transfer mechanism, enabling interactive file transfers and the use of visual file managers like FileZilla with TLVC.

You should verify that the ethernet interface was actually configured correctly during boot by looking at the console boot messages which should show one or more of these lines (depending on your configuration):

eth: ne0 at 0x380, irq 9, (ne1k) MAC 00:1f:11:02:60:2d, flags 0x80
eth: wd0 at 0x320, irq 11, ram 0xcc00, (wd8013) MAC 00:00:C0:BC:8F:4B, flags 0x80
eth: 3c0 at 0x300, irq 15, (3c509) MAC 00:a0:24:67:7f:b1 (HWconf: 330/9), flags 0x80

Use the ps command to check that the network is up and running (look for the ktcp-process and the telnetd and ftpd daemons):

# ps
  PID   GRP  TTY USER STAT CSEG DSEG  HEAP   FREE   SIZE COMMAND
    1     0      root    S 3240 33ef  3072   2012  12864 /bin/init 4
   22    22    1 root    S 3564 36ff     0   1966  13136 /bin/getty /dev/tty1
   23    23   S0 root    S 3cca 71d3  1164   8860  66688 -/bin/sh
   24    24   S1 root    S 3cca 76e0  1164   8788  66688 -/bin/sh
   11    11      root    S 513b 63b2  3072  32690  75696 ktcp -b -p wd0 10.0.2.15 10.0.2.2 255.255.255.0
   15    15      root    S 5591 4c2e     0   1996  15376 telnetd
   18    18      root    S 5c26 5719     0  11406  32992 ftpd
   27    23   S0 root    R 4e67 5f9f  1024   1188  13568 ps
#

If it's not, run the net start command, and check for errors in the output:

# net start
Starting networking on wd0
ktcp -b -p wd0 10.0.2.15 10.0.2.2 255.255.255.0
ktcp: ip 10.0.2.15, gateway 10.0.2.2, netmask 255.255.255.0
ktcp: /dev/wd0 mac 00.00.c0.bc.8f.4b mtu 1500
Starting daemons 'telnetd' 'ftpd -d'
#

net start and the corresponding net stop commands are automatically run at startup if net=xxx is included in the TLVC config-file /bootopts, ´xxx´being one of ne0, wd0, 3c0. The same configfile includes other options that define the network configuration. For more information, check out the chapter on Boot options in the main wiki. Here is a sample working /bootopts file:

## boot options max size 511 bytes                                              
console=ttyS0,38400 debug net=ne0 3 # serial console, multiuser, networking     
#TZ=MDT7                # timezone                                              
#QEMU=1                 # ftpd on QEMU                                          
HOSTNAME=tlvc1          # set network IP from /etc/hosts                        
LOCALIP=10.0.2.16       # This machine's IP address
GATEWAY=10.0.2.2                                                                                                                       
ne0=9,0x380,,0x80
#wd0=11,0x320,0xCC00,0x80
#3c0=15,0x300,,0x80
netbufs=2,1
chs0=980,4,17
#comirq=,,7,10
#init=/bin/init 3 n     # multiuser serial no /etc/rc.d/rc.sys                  
#init=/bin/sh           # singleuser shell                                      
#console=ttyS0,19200    # serial console                                        
#root=hda1 ro           # root hd partition 1, read-only    

Which daemons to start automatically is configured in the /etc/net.cfg file. The examples in the file are reasonably self-explanatory. Note that the httpd daemon has to be enabled manually.

Network Configuration

The system allows for many ways to tune the network - low level and application level. Many but not all these tuneables are available via the bootopts file as exemplified above. Some of them, like the NIC (network card) configuration, may be obvious, others require more of an explanation. Keep in mind that the NICs have their own man-pages with plenty low level details.

Here's a list of important network configuration considerations and non-obvious options:

  • In order to keep the kernel as small as possible, use menuconfig to enable/disable just the interface(s) you need.
  • The NICs are auto-configuring, which means that the system looks for them at boot-time and configures those found. Activation occurs later.
  • The installed NICs must be configured to use the IO address specified in bootopts files, or - if there is no bootopts line for the NIC, the setting in the ports.h header file. And exception from this rule is the 3Com 3C503 NIC (el0), which allows the IO address from bootopts to override the preprogrammed address.
  • Only one NIC may be active at any time. You can switch between them at run-time using the net stop and net start commands. E.g. to switch from the currently active interface (say, ne0) to the wd-interface, use the command net stop; net start wd0. And then, if you'd like to switch back, net stop; net start ne0.
  • If the net= option is found in the bootopts file - like net=ne0- the system will run the net ne0 command at startup time and configure the network according to the settings in the /etc/net.cfg file. Otherwise the net must be started manually.
  • Some times, in particular when looking for boot problems, it is convenient to just turn off a NIC without going through the hassle of building a new kernel. The IO address part of the configuration line in bootopts may be set to zero to achieve this, as in ne0=9,0x0,,0x80. When booting, the kernel will report the interface as 'disabled'.
  • Use the QEMU=1 directive if running on QEMU and intending to use ftp.
  • The netbufs= directive instructs the kernel to allocate the specified number of receive and transmit buffers (respectively) for the NIC. See the next paragraph for details about this.
  • The IRQ line for NICs is not allocated at boot time but rather when the network is started. This allows all (currently 3) network interfaces to share the same IRQ. This means that the kernel's boot message about a NIC found (as in eth: ne0 at 0x320, irq 2, (ne1k) MAC 00:1f:11:02:60:2d, flags 0x80, bufs 2r/0t), doesn't mean the NIC will work, but that a NIC of this type was found at the given address (the proof of the pudding being the reported MAC address). The IRQ has not been assigned at this time, and thus not tested.
  • Be aware that the 3Com el0 NIC may not give up its IRQ line when shut down. There isn't much to do about this. These interfaces were not made to do this at all, it's not part of any specification. The fact that it works on some of them is a strike of luck, not by design.

The 'netbuf=' directive

The Ethernet NIC drivers were created to not use buffers, but rather transfer data directory from user/process space to/from the buffers on the NIC cards. This works well, but limits performance in many situations. Thus the ability to use buffers was added. At the time of writing, the ne2k driver is the only one supporting this, but the other interfaces will be added to the club in 2024.

The addition of 'dynamic' network buffering opened up a number of options which were too tempting to not take advantage of. These are sweet in the netbuf.h file in the arch/i86/drivers/net` directory. The following excerpt from that file explains the basics:


/* Buffer configuration for TLVC Ethernet NICs
 *
 * There are 3 buffer strategies:
 * - No buffers: The driver is moving data directly to/from the requester
 *	(via far mem move).
 * - Static buffers: The number of send and receive buffers specified in the
 *	NET_OBUFCNT and NET_IBUFCNT defines are allocated statically at
 *	compile time. The BUFCNT numbers may be 0, in which case the driver
 *	will run as if NO_BUFS was set (except the extra code is compiled in).
 * - Heap allocation: Buffer space is allocated from the kernel heap, which 
 * 	is slightly different from static allocation in that memory is 
 * 	allocated only if the network is running. Memory consumption will be 
 * 	slightly higher because of the headers in the heap allocation.
 *
 * When HEAP allocation is used, the # of buffers may be set in /bootopts via
 * the 'netbufs=' directive. 'netbufs=2,1' means 2 receive buffers, 1 transmit
 * buffer. The kernel will not do sanity checking on the netbufs= numbers,
 * it's entirely possible to make the system unbuutable by requesting too many
 * buffers. 2,1 or 2,2 are reasonable choices for regular usage. Again, zero is
 * a valid selection and will turn off buffers entirely.
 * When using heap allocation, a header strucure per buffer is also 
 * allocated from the heap, 6 bytes per buffer.
 *
 * AGAIN: zero buffers is always a valid choice - which complicates the driver 
 * somewhat but makes benchmarking much more convenient.
 */

The default setting is to use heap allocation, which is the most flexible since it allows you to turn off buffering and reclaim all the memory without recompiling the kernel.

How many buffers should be allocated? On TLVC, RAM is a scarce resource - as is performance. netbufs= is a very convenient tool to balance the two - and not the least, to experiment. Remember though that the bootopts file and thus the netbufs= setting is read at boot time only. Changes need a reboot.

In general, a 2,1 setting (2 receive buffers, 1 transmit buffer - each buffer can contain a complete Ethernet packet, 1536 bytes) is good. Experiment with 0,0 to see if buffering is contributing at all, your mileage will vary wildly depending on the speed of the machine. The slower the machine, the more valuable the receive buffers, and the less valuable the transmit buffers. On a PC/XT, 3,0 is good. On a 386 @25MHz or higher, 2,1 or 2,2 is good (at the time of writing , the jury is still out on the value of more than one transmit buffer given the internal architecture of the kernel).

More considerations about speed, buffers and balance in the section about ktcp below.

Networking Software

ktcp

TBD

Ethernet Drivers

TBD - For now take a look at the man-pages for the available drivers, wd, ne, 3c. Remember that these man-pages are available from your development directory on the host, by using the eman command.

Debugging Tips & Tricks

TBD

Planned enhancements

  • Add net buffer support to all drivers
  • Add UDP support

TLVC File Transfer Guide

Serial communications

Transferring limited size ascii files can be done with reasonable reliability via serial lines and terminal emulation. Using cat > filename on TLVC and then pasting text into the terminal is reasonably efficient. If this fails marginally (losing a few bytes here and there), turn off echo in order to reduce the interrupt load on the system:

stty raw; cat > filename; stty -raw

or use the sercat command:

sercat > filename

Terminate such transfers with ^D (EOF).

To check whether the transfer was error free, use the sum command at both ends, after ensuring that the byte count is exactly the same (ls -l). Note that it takes only an extra newline or CR at the end of the file to make the sum command useless.

Even binary files may be transferred this way by first converting them to ascii. Use the hexdump command on Linux:

hexdump -e '"%06.6_ax:" 8/1 " %02x" " " 8/1 " %02x" "  " ' -e '16/1 "%_p" "\n"' "$@"

to create the ascii file, then transfer it and use hd -r on TLVC to convert it back.

A far more efficient (and traditional!) way is using uuencode and uudecode. Instead of turning 16 bytes into 69 which hd does, uuencode converts 2 bytes into 3 ascii characters. The commands are part of the uucp package. The (simplified) syntax is

uuencode newname < inputfile > outputfile

where newname is the filename to be used when the file is decoded and recreated. Even the filemode (protection codes) is stored in the encoded file and will be restored during decoding – if possible. To decode, simply give the command

uudecode < inputfile

and the original file (and filename + modes) will be recreated. There are many options to override the defaults, check the man-pages for details.

Transferring text or uuencoded binary files from TLVC via serial is usually easy (and reliable) since most systems will have no problems keeping up with the speed of the TLVC system.

Mechanisms to make serial transfers binary and fully reliable - Kermit, X/Y/Z-modem etc. - are forthcoming.

FTP - client and server

ftp client

The interactive ftp client works like most ftp-clients for Linux, Unix and other OSes. Please refer to Linux ftp-man pages for general info. The following paragraphs discuss the exceptions to the 'standard'.

Command line options The ftp-client recognizes the following command line options:

-u - username
-p - password
-P - Start in PASV (passive) mode. This is the default.
-A - Start in PORT (active) mode
-i - Disable multifile prompting.
-q - Qemu mode, normally set automatically via the environment-variable QEMU, see below.
-v - Verbose mode, equivalent to debug = 1, which is now the default.
-d - Debug on. The default debug level is 1, repeat -d to increase the level top max 4.

Thus a typical command line for ftp may be

# ftp -u user 10.0.2.2 5050

or simply

# ftp

The former will connect to the given host or address and prompt for username and password, like this:

# ftp -u myusername 10.0.2.2 21                                                 
Connected to 10.0.2.2.                                                          
220 raspi2b FTP server (Version 6.4/OpenBSD/Linux-ftpd-0.17) ready.             
Name (10.0.2.2:myusername):                                                     
Password:                                                                       
530 Login incorrect.                                                            
Login failed: 530 Login incorrect.                                              
ftp>

The port number is optional, default is 21.

If ftp is invoked without arguments, the open command establishes the connection:

ftp> open 10.0.2.2                                                              
Connected to 10.0.2.2.                                                          
220 raspi2b FTP server (Version 6.4/OpenBSD/Linux-ftpd-0.17) ready.             
Name (10.0.2.2:ftp): username                                                      
Password:                                                                       
230-                                                                            
230- The programs included with the Debian GNU/Linux system are free software;  
230- the exact distribution terms for each program are described in the         
230- individual files in /usr/share/doc/*/copyright.                            
230-                                                                            
230- Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent          
230- permitted by applicable law.                                               
230 User helge logged in.                                                       
Remote system is Unix/Linux, using binary mode                                  
ftp> 

The commands currently supported by TLVC ftp are:

ftp> help                                                                       
directory:      List remote directory                                           
ls:     List remote directory                                                   
get:    Fetch remote file                                                       
mget:   Fetch multiple remote files                                             
put:    Send file to remote                                                     
mput:   Send multiple files to remote                                           
cd:     Change (remote) working directory                                       
pwd:    Show (remote) working directory                                         
bin:    Set file transfer type to BINARY                                        
ascii:  Set file transer type to ASCII                                          
quit:   Quit program                                                            
type:   Show file transfer type.                                                
prompt: Toggle interactive multifile transfers                                  
debug:  Set debug level 0-4 or 'off'.                                             
bye:    Leave program                                                           
!:      Invoke shell to execute local command.                                  
?:      Alias for help.                                                         
help:   Print this.                                                             
close:  Close connection.                                                       
open:   Open new connection, log in.                                            
mkdir:  Create remote directory.                                                
delete: Delete remote file.                                                     
verbose:        Toggle debug off or 1, default 1.                               
status: Show status, modes etc.                                                 
lcd:    Change local working directory                                          
glob:   Toggle globbing                                                         
passive:        Toggle passive/active mode                                      
ftp> 

Commands may be abbreviated to 3 characters.

Note the difference between bye and close: The former exits the program, the latter just closes the connection, and ftp is ready for a new open command. ^C will terminate the program.

ftp in QEMU

ftp (and the TLVC ftp server) take special measures to work seamlessly within QEMU. The qemu.sh script that comes with TLVC includes mapping necessary for the ftpd server to support passive connections:

# Simultaneous telnet, http and ftp forwarding
FWD="\
hostfwd=tcp:127.0.0.1:8080-10.0.2.15:80,\
hostfwd=tcp:127.0.0.1:2323-10.0.2.15:23,\
hostfwd=tcp::8020-:20,\
hostfwd=tcp::8021-:21,\
hostfwd=tcp::8041-:49821,\
hostfwd=tcp::8042-:49822,\
hostfwd=tcp::8043-:49823,\
hostfwd=tcp::8044-:49824,\
hostfwd=tcp::8045-:49825,\
hostfwd=tcp::8046-:49826,\
hostfwd=tcp::8047-:49827,\
hostfwd=tcp::8048-:49828,\
hostfwd=tcp::8049-:49829"

With this setup, the command to connect to TLVC from the QEMU host is ftp -P 8021 localhost. Make sure QEMU=1 is enabled in either /bootopts or /etc/profile. The only limitation is that outbound ftp (from TLVC) requires passive mode (the default). Currently, when in QEMU-mode, the ftp-server will turn debug on, which means extra output to the console. This will eventually go away.

FTP server

The FTP server (aka ´ftp daemon´) is normally started automatically with the net start command. It will accept connections on the standard ftp port and supports both passive and port (active) modes. It requires the external user to log in, but neither checks the username or the password at this time, so you can use whatever default comes up or just empty lines.

The server implements most of the regular ftp commands and will tell you if a command is not implemented. In most cases it will detect if the remote client is Linux or Unix, and set binary (image) mode automatically. The SITE command is supported and enables (among other things) a file transfer delay to be specified, which enables file transfers between TLVC systems to run reasonably smooth. In most cases, such delays (on client and server sides) are set automatically because the programs recognize the TLVC platform as a special case.

Likewise, the server will check for the QEMU environment variable and make adjustments accordingly (see above).

MORE ABOUT SPECIAL SERVER COMMANDS <<<<

Other file transfer commands

Before TLVC had fulle native client and server ftp support, other means were used to get data back and forth. Not as flexible and interactive as ftp but useful - and in some cases still the easiest.

urlget

urlget is a very flexible tool for transferring files to or from TLVC, and particularly well suited for inclusion into scripts. Four programs in one – urlget, httpget, ftpget and ftpput, supporting 3 different URLs and 3 protocols: HTTP, FTP and pure TCP (useful with netcat) - all requiring a server to talk to at the other end. Not a problem - if such a server is not already running, a python one-liner is normally all it takes to start your own. Which frequently turns out to be preferable even when such server is already running – because you get access to you own home directory. More about that below.

A summary of the command syntax:

urlget http://host:port/filepath
urlget http://username:passwd@host:port/filepath
urlget ftp://host/filepath
urlget ftp://username:passwd@host[:port]/filepath
urlget tcp://host:port/filepath

httpget [-h] [-d] [-p] host filepath
ftpget [-v] host[:port] filepath [username [passwd]]
ftpput [-v] host[:port] filepath [username [passwd]]

For all variants, the authentication can be omitted if acceptable to the server. If included, note that the username and password are sent in plaintext over the network. Also, port may be omitted in most cases, in which case the default port is used - 80 for http, 21 for ftp. For tcp, the port must be included as there is no standard. For ftpget, if the filepath ends with a slash, a directory listing is delivered. The -v option extends the file listing to long format (ls -l). For http, the -h option will include HTTP-headers in the output, -d will discard the contents, which is meaningful only with the -h option (display headers only), and the -p option will post (send) data instead of fetching it. The data in this case is whatever follows a '?' in the filepath. This option is currently not very meaningful. ftpput will create new directories as needed and if permitted. ftpput 10.0.2.2 /tmp/bin/sh name passed will create the tmp and bin directories (relative to the current directory) if they don't exist

The tcp-url sends the file name, but there is no standard way of handling such request at the other end, see below for a suggestion on how to use this variant. This chapter also discusses ways to set up your Linux or MacOS host to communicate with TLVC.

OUTBOUND HOWTO

If running QEMU, use the default qemu.sh script and make sure this line is 'uncommented': NET="-netdev user,id=mynet,$FWD -device ne2k_isa,irq=12,netdev=mynet"

urlget with http, httpget

  • Start a web server on the host, like a simple python http-server:
    • If you have python V3, run python3 -m http.server 8000 --bind 127.0.0.1. If your version is 2 (check by running python -V or resort to v3 explicitly if it exists, like python3): python -m SimpleHTTPServer. If running Windows, the commands may be a little different, Google it to find out.
    • This will make the current directory available for file transfers.

I you want something more 'durable', install and run lighttpd (see below). If using the default install- and config-files, the files to transfer would be placed in a subdirectory of /var/www/html - such as /var/www/html/tlvc. In this case you don't need to specify the port number (8000 above), or just add '80' (default) for the record. Make sure to create the tlvc subdirectory and set the access bits. This installation requires root access.

  • Put the file(s) you need to transfer into that directory (or a subdirectory).
  • Run
    • [python3/python] urlget http://10.0.2.2:8000/filename > local_filename or urlget http://10.0.2.2:8000/dir1/dir2/filename > local_filename
    • [lighttpd, other servers] urlget http://10.0.2.2/tlvc/filename > local_filename

urlget with ftp, ftpget If an ftp server is already running, you're OK. Check the server config-files to determine if anonymous access is available, and what directory such access is limited to. If you will be using authentication (username and password), ensure your user is allowed incoming ftp access.

FTP: If no ftp-server is running, apython-based server is the easy way out, just like the http-example above. pyftpdlib must be installed, google it if directions are needed. Run python3 -m pyftpdlib -p port -u someusername -P somepasswd (see the online docs for details). Any name and password will do, not limited to your local username/passwd, but they must match when making a connection. Anonymous authentication is supposed to work, but does not. The default port number is 2121. Also, be aware that this ftp-server does not support wildcards.

Assuming an FTP server running and your user is an allowed ftp-user, you can ftp files into TLVC like this:

urlget ftp://user:passwd@host:port/filename > localfile

for example

urlget ftp://testuser:passwd@10.0.2.2:21/testfile > localfile

The port number (in this case :21) is optional. 21 is the default and may be omitted. If the ftp server supports (allows) anonymous ftp, the username and password may be omitted. In that case the public (anonymous) ftp directory is where the file (testfile) will be looked for. Otherwise, if you provide your username and password (they are being sent over the network in clear text!), your home directory is the root directory for ftp. If test file ends with a slash /, then it is assumed to be a directory, and the slash means 'list this directory'. Example:

urlget ftp://user:pass@10.0.2.2/

which will list the users home directory.

Similarly the syntax for ftpget is

ftpget [-v] host[:port] filepath [user [passwd]] > localfile

The -v (verbose) option is meaningful only when listing directories (filepath has a trailing '/').

TCP: In many ways the simplest of all variants is 'raw tcp': All you need is netcat (nc) on the server, which exists on most Unix and Linux systems. On the host, start nc so that it waits for connections and then transfers a file:

nc -l 2323 < tlvcout.txt

2323 is a randomly selected port number (> 1024), which you need when making the connection from TLVC:

urlget tcp://host:2323 > localfile

The port number is mandatory since there is no default. Notice that nc doesn't know when to terminate the connection, so you have to abort it with ^c.

ftpget and httpget urlget may be linked to different names which will affect its behaviour. If you use ftpget it will use the ftp-protocol and the syntax is like this:

ftpget host[:port]  filepath [user [passwd]] > localfile

for example

ftpget 10.0.2.2 filename username userpw > file

Like before, username and password may be omitted if anonymous ftp is supported by the server. And again, if the filename ends with a slash, the name is assumed to be a directory and its content will be displayed. If the command line option -v is used, the directory listing is verbose (like ls -l).

httpget follows the same rules, with syntax as specified above:

httpget [-h] [-d] [-p] host[:port] filepath > localfile

OUTBOUND HOWTO

As mentioned above, files may be transferred out of an TLVC system either using ftp (ftpput) or the local http-server. The latter is non-trivial at first, easy when all is set up.

  • Place the file/files to transfer in the /var/www directory on TLVC.
  • [QEMU]Use curl or wget to fetch the files: [qemu] curl http://localhost:8080/filename > filename.
  • [Physical machine] curl http://10.0.2.15/filename > somename

In order to access files not in the httpd-directory, symbolic links are useful. For example, if you want to transfer the entire hard disk: cd /var/www; ln -s /dev/hda myfile, then use curl from the other end to fetch myfile. Be warned, this is going to take some time. As of this writing the transfer speed is about 27k bytes per second on a physical system (386/20, NE2K interface).

Using ftpget is simpler, in particular if a ftp-server is already running on the destination machine. The syntax is documented above and is identical to the ftpget variant.