		Magic Keyboard extensions for linux 2.1.x

0) WARNING!!!!!!!!

   This is extreme ALPHA level software. It could do anything to your
   computer! It could delete all your data (although I'd be very
   surprised if it did)! If you use it, it is at your own risk. It
   works for me --- what it will do for you, I dare not say.

   Also, in its current form, this stuff is an ABSOLUTE NONO for any
   security-conscious environment! If you use ssh instead of telnet for
   fear of packet-sniffers, you certainly don't want to run this. If you
   have untrusted user accounts on your machines, you don't want to run
   this. If you are connected to the InterNet, you don't want to run this.

   You have been warned! ;-)


1) THE IDEA
   
   The idea of the Magic Keyboard extensions (MKB for short) was born
   out of necessity, and good weather. I happen to live in Australia, in
   a wonderful house with a veranda, but without an air condition unit.
   As a result of this (and of 4 machines running 24/7), my study is very
   hot during summer, and I longed for doing my work outside. I had an
   old DEC Multia lying around that would be perfect for doing so. Just
   one drawback: It was in a sad state. The harddisk was dead, the floppy
   was dead, and the keyboard controller was dead. That last one is the
   the real problem --- I had it booting from the network rather quickly,
   but I could only use it remotely (and after all, I wanted to use the
   other machines remotely from this one. Oops!).
   I also had my laptop lying around, complete with a working keyboard
   controller, but lacking in CPU and gfx power to run the X server I
   wanted, as well as the ethernet interface. So I needed to somehow 
   make the Dec use the laptop's keyboard, via a PLIP connection.

2) HOW IS IT DONE?
   
   A while ago, Geert Uytterhoeven went through the kernel keyboard
   driver and split it up into a low level and a high level part.
   The low level part passes stuff to the high level part through a single
   function called handle_scancode(). 
   MKB hooks in between the low and the high level driver. By default,
   it acts as a simple pass-through. But when the special device file
   /dev/mkbd is opened, MKB instead sends all low level key scan codes out
   to a user level program through this device file, and in turn passes
   all scancodes written to it (by a user level program) on to the high level
   driver. 

   Now, there is nothing saying that a scancode read from /dev/mkbd on
   a particular machine has to be passed back to that machine. Instead,
   the codes can be sent over any network connection to any machine.
   If they are fed back to /dev/mkbd on another machine, they will look
   exactly like locally created scan codes on that machine. Effectively,
   in such a situation you have a keyboard physically connected to one
   machine, but logically to another.

3) USAGE

   MKB consists of three parts. One is a kernel patch that creates the
   /dev/mkbd device mentioned above. 

   The second part is a daemon, mkbd, that listens on port 1969 for
   connections. When a connection is established, and the originating
   host is in a list of authorized hosts, scancodes read from it are
   directly fed to /dev/mkbd, thus simulating local key events.

   WARNING!!! At the moment, the only authentication done is based on 
              network addresses. This is a huge security hole --- anyone
              on a machine allowed to connect to the daemon can send you
              scancodes! Do _not_ use this where security is a concern!

   The third part is a "client daemon" (now there is an oxymoron!) mkb that 
   establishes connections to a number of mkbd daemons on various machines.
   It also maintains one "current" connection. 
   The mkb daemon opens /dev/mkbd for reading and sends all the scancodes
   read to the mkbd daemon connected to the "current" connection --- with
   one exception. When you hit SCROLL-LOCK, it switches the current connection
   to the next connection it has (wrapping around at the end). This allows
   you to change which machine you (physical) keyboard is logically connected
   to without taking your hands off it.
   WARNING! The scancodes are currently sent unencrypted. Anybody who can
   sniff those packets can see every single key you pressed! Once again,
   do NOT use this if you are concerned about security! If you wouldn't
   want to use telnet to use a remote machine, do NOT use MKB. You have been
   warned!
    
   There is a way to stop the mkb client daemon. If you press the right
   Shift key, then (holding down the shift key) press and release the 
   "Pause" key, and finally release the Shift key, the mkb client daemon
   will exit. I am not sure whether this is ever needed, but it seemed like
   a good idea idea to have some way out if your mkbd daemon suddenly decided
   not to pass stuff on anymore. This might go away, as I haven't really
   ever needed it, and the current implementation is really ugly.

4) INSTALLATION

   First of all, use the enclosed patch against your kernel (it is
   against 2.1.57, but I have good hopes that it patches cleanly into
   earlier and later kernels as well --- it mainly adds stuff, it doesn't
   change much). Recompile your kernel (enabling the magic keyboard extensions
   in "make config"), and create the character device file /dev/mkbd with 
   major 10 and minor 196.
   Then do a "make depend" and "make clean", followe by "make all". This
   should create the two daemons, "mkbd" and "mkb". 

   Now you can start a little experiment. Execute
   
     ./mkbd my_hostname

   (with my_hostname being your hostname). If all went OK (i.e. you didn't
   get any error messages), the daemon will go into the background. You
   should then execute

     ./mkb my_hostname

   Unless you see any error messages, you are now running the magic keyboard
   extensions! You probably don't notice it at all (if you do, something is
   wrong), but when you do

     cat /proc/mkbd

   it should look something like this:

      bytes in buffer	: 00000      
      bytes passed on	: 125198
      number of processes	: 00001

   (Note: the number of bytes passed on is probably smaller for you ---
   I have been using it for a while). The important part is the "number
   of processes" row --- that one process is the mkb client daemon.

   If that all works out, do a 

      killall mkb
      killall mkbd

   (don't do it the other way around --- you wouldn't be able to type the
   second killall!). 

   Copy the daemons into some directory in your PATH. 

   Now repeat those steps for all the machines you want to use MKB on
   (I have tested it on linux/x86 and linux/AXP. It should work with
   other architectures that use standard PC keyboards).

5) SETUP
  
   Setting up MKB to share keyboards between different machines is
   very easy. Basically, you start an mkbd daemon on each machine that
   is supposed to _receive_ redirected scancodes. In my case, those are
   wombat, platypus, ostrich, possum and wallaby. Keyboards I might use are
   attached to wombat, ostrich and possum. So on wombat, I execute:

   
     wombat:>  mkbd wombat ostrich    # it doesn't use possum's keyboard

   on platypus

     platypus:>  mkbd wombat ostrich  # neither does platypus
   
   and so on:

     ostrich:> mkbd wombat ostrich possum  # order doesn't matter
     possum:>  mkbd possum  # this is the laptop, uses only its own keyboard
     wallaby:> mkbd possum  # the Multia with the dead keyboard controller,
                            # it just uses the laptop's keyboard

   Note that starting the daemons doesn't change the way the machines
   work at all. At this point, they are all still using their local
   keyboards, without even going through userspace. The reason is that
   the mkbd daemons only open /dev/mkbd for a very short instant once
   a scancode is received.

   Now, the client daemons have to be started. For wombat, this is done
   by executing

     wombat:> mkb wombat platypus ostrich 

   For the client daemon, the order of its arguments _does_ matter.
   Directly after startup, it sends scancodes to the first mentioned 
   host; Pressing Scroll-Lock will switch to the next one, wrapping
   around at the end of the list.
   It is usually a good idea to have the local mkbd daemon listed as
   the first recipient --- that way, starting mkb is absolutely transparent
   until you hit Scroll-Lock.

   Similarly, the other two client daemons are started as follows:

     ostrich:> mkb ostrich wombat platypus     
     possum:>  mkb possum wallaby ostrich

   You can do this by hand, or (if you are really brave), you can put it
   into your rc.local files (I haven't tested this yet --- I don't reboot
   often enough).

6) FEEDBACK

   I would be extremely interested in feedback. In other words --- if you
   are using MKB, and it doesn't work well for you, mail me. If it _does_
   work well for you, mail me too ;-) If you have any suggestions for
   improvements (or patches to implement badly missing features *hint hint*),
   by all means: Mail me!

7) BUGS

   I am currently aware of just one bug --- the state of the keyboard LEDs
   is a per-VC state. When your keyboard is logically connected to a different
   machine than physically, the keyboard LEDs will display the state of the
   machine it is physically connected to. I am not yet sure what to do
   about this. Basically, I have two ideas:
     a) implement a state-forwarding from the mkbd daemon to the mkb client
        daemon, making the LEDs match the state of the logically connected
        machine, or
     b) Put away with the original meaning of the LEDs (I don't use any
        of those features, anyway --- my CAPS LOCK key is a second TAB
        key), and instead use them to indicate which machine the physical
        keyboard is connected to logically.
   Option (b) is more appealing to me, and it is easier to implement, too.
   However, I am not sure if other people do actually rely on those LEDs?!?
   Comments?

   Other than that --- both mkb and mkbd use syslog() to log whenever
   something goes wrong. So if you run into trouble, look there first.

8) LEGALESE

   All Code is under the GPL, any version you chose. You are on your own.
   No responsibility whatsoever is accepted. Using MKB, you acknowledge that
   you have been warned about security issues. 

9) CONTACT DETAILS

   You can contact me at bmeyer@cs.monash.edu.au
   Or by snail mail at

      Bernd Meyer
      Department of Computer Science
      Monash University
      Clayton, VIC 3168
      Australia

   If your mail concerns MKB, it would help if you put MKB into the
   subject, so that I can seperate it from my usual mail. Thanks!

10) TRIVIA

   If you are really really really thankful for MKB and want to do something
   nice for me --- here are some ideas:

     * Contribute! Patches, Ideas, Ports, whatever
     * Got a pretty postcard of your hometown? So I can see where MKB is
       being used?
     * I _love_ Plush animals. Do you have one that is native to your
       country?
     * I love real animals, too (as if you couldn't tell from the examples ;-)
       --- a donation to the WWF is always a good idea.
     * Got any good board games in your country? That come with English
       or German rules? I am a sucker for board games....

   But basically --- I'd just love to heat that someone is actually
   using this stuff.

   Oh, and one more thing --- I know that "ostrich" should be called "emu".
   I was really tired when I named that machine.......
 
TODO:
=====
* Modularize the mkbd driver. Should be very easy.
* AUTHENTICATION! 
* Keyboard LED handling
* Cofiguration file support
* Check for keyboard handling on architectures other than x86 and AXP
* Reduce network overhead?

IDEAS:
======
* User level Interface for pseudo-keyboards
  + speech recognition?
  + footpedals for Shift/ALT/Ctrl?
  + chorded keyboards?
  + serial terminals in "PC scancode" mode?
* Interface to gpm for mouse-forwarding (at the moment, you need a mouse per
  machine)
* Windows95 keyboard driver that behaves like mkbd (I'd love to have this,
  but can't do it myself. I don't program in Windows)
