>-----Original Message----- >From: openvpn-devel-ad...@lists.sourceforge.net >[mailto:openvpn-devel-ad...@lists.sourceforge.net] On Behalf Of Iftikhar Qureshi >Sent: Thursday, March 16, 2006 12:34 PM >To: openvpn-devel@lists.sourceforge.net >Subject: [Openvpn-devel] OpenVPN for PocketPC > > >I was wondering what does it take to write an OpenVPN client/driver for >PocketPC. > >I looked at the 'Porting Notes' section on the website. Still not sure >what minimum modules I'll have to compile for PPC. If >any of you could >guide me on what is involved. > >Once I have enough information I'll see if I got what it takes to write >the client - otherwise - :) > >Salamz, >-IQ
Iftikhar; Funny you should mention that as I have been working on this for the past two weeks. Here is what I have found out along the way, and also what I have done/am doing. This will be a bit long, so let me tell the synopsis first; then anyone can read the details later if they care. Summary: Built a port of the TAP driver first since that seemed the most questionable. I implemented the parts I thought might be show-stoppers, but left incomplete for now some parts I know can be implemented for later, after I have the user-mode stuff working to stimulate the driver. Have been working for the past week on the user-mode side of things. I have just now been able to build it to completion, and can at least run the --version and --help option successfully (whee). Need to do: testing of all the compatibility routines written, rework tun.c to reflect different TAP interface, go back to TAP and complete implementation of stuff I deferred. OK, here is more detail: TAP driver: * the existing win32 TAP driver is basically an NDIS miniport. CE (PocketPC underlying OS) supports much of the NDIS driver model, however there is an extension to NDIS being used which is not available. This extension comes in the call NdisMRegisterDevice() which is used to create a device object which the usermode app can open via CreateFile and do stuff via ReadFile/WriteFile/DeviceIoControl. Without it, usermode can't access the device to provide the 'lower edge' functionality. If you're curious, this extension was apparently added to facilitate creating things like 1394 ethernet adapters. I worked around this by also creating in the tap device a 'stream device' in CE parlance. It loads as a separate device driver (though implemented in the same dll) and provides the common file IO through a device named 'TAP0' (and higher digits). * the existing architecture in the win32 port depends on asynchronous IO, or 'overlapped IO' as it is called. CE, however, does not do overlapped IO at all. Couldn't manually implement it either, because the LPOVERLAPPED passed into ReadFileEx is discarded and never makes it into the driver's servicing routines. I'm dealing with this now with an interim solution for now, with a better solution later. The short term solution I effected was to make the ReadFile call fundamentally asynchronous returning with either: success, and a full packet read success, and 0 bytes read (meaning no packet available) failure, meaning there was a packet but the buffer was too small all other failure having the usual meanings I did this because it was easy and I wanted to move on to other porting activities since I can't do much testing without the user-mode interface or a test harness built. This is suboptimial since it is essentially a packet polling interface, but it's temporary. The long term solution I am planning is to ditch the ReadFile interface altogether, and implement a custom asynchronous IO via an ioctl() interface. This should have similar performance to the existing mechanism, and I think can have a somewhat similar call sequence to the overlapped IO mechanism. I'm concerned about the event handles, though, because unlike NT, the calls aren't made in the process context of the calling process. Rather threads 'migrate' from one process to another, and the device drivers are in a different process called device.exe. Weird! So I wonder about the validity of a handle created in one process and being passed-by-value to another. It might work but I think regardless it can be handled by having the events brokered by the driver, and exposing a 'create', 'wait', and 'close' api to be used with the custom asyncronous read. * There's also some more pedestrian aspects, like completely different registry settings, and stuff involving IRQLs which are not relevant in CE. Building CE TAP Driver: * I'm using eVC4 to build. Drivers in CE are dlls, which personally I find a bit nice. There is not a DDK per se, but there is something similar in the form of the Platform Builder, which is what OEMs use to create the OS image for their devices. There's headers and some import libraries in there that are needed to link in the NDIS stuff since they aren't included in the regular eVC install, alas. State of CE TAP Code: The code is a bit of a mess at present. I hacked on it quite a bit while trying stuff out. I plan to clean it up to minimize diffs after I get it finally working. User-mode component: The user-mode component is written in very nice portable C, however every OS has it's peculiarities. CE is highly peculiar. In fact most of the past couple weeks has been on the user-mode part, though not all of it openvpn, but rather the dependencies. Let me start with the dependencies because this will save you discovery time in you're interested in trying to build or work on that. Oh wait, first let me describe configuration briefly: Configuration: I am building all the libraries as static libraries for now. This makes it easier for me for debugging. I might create a dll-based configuration in the end after all is said and done. Targeting ARM and Emulator. I do most of my initial development and testing on the emulator. For starters at least I am using the eVC project file mechanism (as opposed to make files) except where noted. I can produce make files in the end, when all is said and done, but makefiles give me headaches. Also, for now at least, I am building openvpn as-is, i.e. as a console application. Ultimately I would like to make a super-easy-to-use GUI interface but figure that can wait until there's something working to interface to. As you know, PocketPC does not have a console, however. So I am using PocketConsole from SymbolicTools and the related PortSDK. FWIW, they don't seem to be developing it anymore, and it's not open source, but it suffices for now I think. Oh, and I don't think it works correctly on VGA devices. LZO library: Easy. Throw the source in a project and hit build and out comes a lib like it should. I'm a little surprised because I had to futz with UCL before to get it to build, but I'll take it when I can get it. OpenSSL library: Spent more time on this one. First, the latest release has official CE support, which was definitely a time-saver. There appears to be a defect in the makefile spewed out for the emulator however and I had to manually edit it to get it to work. Before you get to that point though.... You have to download the PocketConsole, and some compatibility libraries you will have to build. The web page will tell you what you need and has links. I should note that I had to edit the WCEemulator.bat that is normally installed as part of eVC. This batch file (and WCEARM.bat) are used to setup the command-line environment when building stuff from nmake, which will be happening for OpenSSL and it's dependencies. Near the bottom is a variable: set TARGETCPU=emulator Which I could not get to work, so I commented that out and changed it to set TARGETCPU=X86EM Which then did work. Mostly. Actually, one of the dependent libraries uses that to build constructs a path based upon that variable (can't remember which, I think wcecompatlib) and I had to edit it's mak file and I think make a copy of a lib directory in the WCE Tools area. I'll have to check back later, but your compiler and linker will barf and let you know what's not in order. It's easy to fix once you're aware it's easy. On to Open SSL. You will need to install ActivePerl to run the perl scripts that are part of the build. The instructions given on the web page are correct. I built: * pocket console, static * compatlib, static * compatlib, dll I'm only using the pocket console versions for current development because, as I mentioned, I figured GUI stuff can be done later. There is a couple gotchas: * at about line 58 of opensslconf.h (which is spewed out during configuration) that the ENGINESDIR and OPENSSLDIR are set to things that are appropriate for desktop systems. In particular, there was a drive letter. CE doesn't use drive letters. I checked and made them the usual unix path which should also be fine for CE. #define ENGINESDIR "/usr/local/ssl/lib/engines" #define OPENSSLDIR "/usr/local/ssl" I don't know if it's critically important * the emulator build won't work. The makefiles generated are almost correct, but not quite. You will have to edit them manually before you invoke nmake. In particular, you will need the following to read: Around line 27 EX_LIBS= winsock.lib $(WCECOMPAT)/lib/wcecompatex.lib coredll.lib corelibc.lib Around line 33 LFLAGS=/nologo /opt:ref /subsystem:windowsce,4.20 /machine:IX86 /NODEFAULTLIB:libc.lib /NODEFAULTLIB:oldnames.lib Around line 70 MLFLAGS= /nologo /opt:ref /subsystem:windowsce,4.20 /machine:IX86 /dll /NODEFAULTLIB:libc.lib /NODEFAULTLIB:oldnames.lib Then they will go. openSSL! Hurray! OK, then now you are ready to start working on the openVPN source. I created a console app with the wizard in the PortSDK which generated a hello world app. Do it as an ANSI app. The StdAfx.h that it generates has three #includes which are important to include somewhere to get the console stuff in, and the rest can be discarded. I stuck them in config-win32.h initially, but moved them later as described... ah... later. You will need to modify that file to alter some of the config options. I conditionally compile with the definition: #ifdef UNDER_CE Which is the standard 'this is CE specific' #define. It is already in your project. Also, you will need to define WIN32 which is _not_ standard on CE, but seemed to be cleaner than hacking all the source files to modify the tests. You will need to modify HAVE_CHDIR HAVE_FCNTL_H To not be defined, and LZO_HEADER_DIR to be defined. Well that actually depends. I needed it. It affects wether you have an lzo subdirectory under your standard include with the lzo stuff. I happen to. Near the bottome, where there is the #include <direct.h> is where I started putting in my CE specific portability code. It became large so I broke it out in a separate file. That region now reads: //wild CE portability stuff //HHH #ifdef UNDER_CE //additional api emulation and the like needed for win ce #include "wince_portstuff.h" #else #include <direct.h> #endif A modified very little of the rest of the source. I had to modify cryptoapi.c to #include "config-win32.h" to pick up the portability code, which previously it had not. I know I had to modify win32.c, which I haven't finished I don't think, and misc.c had some environment stuff. I'm a little worried about that because CE does have environments, but hopfully it won't matter. As mentioned, the portability code became extensive enough that I broke it out of the config-win32.h into a separate header, wince-portstuff.h. There is a matching wince-portstuff.c with implementation. Oh, by the way, you won't need to include memcmp.c in your project. Minor detail. At this point you will have a cornucopia of build errors and (eventually) linker unresolved symbols. Rather than going into details and making the email longer than usual, I'll leave it to the asker to request the details of the stuff added to make it build in link. The short story is: You will need to implement all the 'low-level c runtime' functions. This means things like open() read() write() stat() etc. This is a chore. I hope my implementation works, it's going to be some debugging to prove it though. In short I faked low-level API as a warpper around the 'stream io' calls like fopen, etc. Happily those are present in CE. I'm not sure about my conversion of mode bits to the open mode string that fopen uses, though. I'm a bit dubious in my implementation of open_osfhandle(). I'll leave out the details here unless asked but there is a method _wfdopen() available which is curious because it is defined as _taking_ a low-level handle, but we know PocketPC doesn't have those (or we wouldn't have to be implementing this stuff) so I /assume/ that really it takes an OS handle. In which case I can use it (since my fake low-level handles are really FILE*). _fdopen is a noop in this scheme. More tedious is all the API stuff that needed changing. It's a little like porting NT to Windows95 because 95 doesn't have unicode functions. Well, this is the same thing but the opposite: the openVPN is ANSI, but CE is UNICODE only. So a bunch of methods have to be wrapped with ANSI wrappers and string translation done inside. To complicate matters, the headers define those ANSI functions, but they don't exist. This means when you implement them you will have a collision definition since the headers declare them as declspec(import) which you will not be doing. As a work-around I did, for each, a version with the prefix CE_, and the #undef'ed the api name and then #defined it to my new name. Here is an example of what I mean: //DeleteFileA //misc.c BOOL WINAPI CE_DeleteFileA ( LPCSTR lpFileName ); #undef DeleteFile #define DeleteFile CE_DeleteFileA The following have to be treated in this manner: FormatMessageA CryptSignHashA CreateFileA DeleteFileA RegQueryValueExA RegEnumKeyExA RegOpenKeyExA CreateEventA CreateSemaphoreA Interesting exceptions are: LoadLibraryA, which you can just implement directly without the trick above, and GetProcAddressA, which doesn't need the CE_ prefix hack, but curiously does still the the #undef and #define because it is unconditionally #defined to the wide-char version regardless of build flags. Odd. Lastly, you will need to stub GetOverlappedResult and CancelIo. I didn't bother implementing them because I know this stuff is not going to be present with the CE TAP driver -- it will use a different mechanism (polling initially, and funky asynchronous IO afterwards). At this point, you should be able to build openVPN to completion. It won't actually work, obviously. I just got to this point today, and only have used the screen printing options --version and --help and a sanity checkpoint. Next steps: * test the portability functions I implemented in wince_portstuff.c to make sure they really work. * study tun.c and figure out what has to be reworked there. * finish the 'deferred' activites in the TAP driver. * test fix test.... Later: * clean code for submission and regress * maybe alternative gui ui And that's it for now. Apologies for the length. Actually it was helpful to me to write it down as a log. -Dave