How to use USB/IP on a wireless router to share USB devices

This problem has been around me since last week (yes, only last week), and now I finally got a solution. Alright I forgot to tell you what the problem was… It was about one week ago , I purchased a printer, along with a TP-LINK WR1043ND wireless router. The router is great. It’s fast and the signal is always full anywhere in my apartment (therefore I doubt whether it’s good for my health…) but anyway everything looked just great.

The problem was that the printer was only USB connectable, which means only one person can use it any given time. Three other people share the apartment with me and they also want access to that printer without bringing laptops around and repeating plugging and unplugging, so there comes a problem. A decent solution is to make the printer a “network printer”. I noticed that my WR1043ND router actually has a USB port, so some thoughts came up to my mind…

The first thing I did was to search for factory firmware updates, for the stock firmware I had apparently did not have USB support for printer sharing. As soon as I found out that there indeed is a official firmware update for this router which enables printer sharing, I downloaded it and gave it a shot. It turned out to be quite annoying because you need to install a software called “TP-LINK printer sharing utility” which basically installs some “magical stuff” into your system and boots every time together with the system. The software actually uses some virtualized driver to emulate a USB port on the computer, and communicates with the router with some privately defined protocol via TCP/IP network. The software requires the printer found on the router to be bind with an actual printer installed on the system, which basically means you will need to connect your computer to the printer to install the driver first and then try out the TP-LINK function via network. Obviously this is to prevent users from accessing non-printer devices connected to the router due to security concerns… the software actually emulates USB packet at the lowest level so theoretically everything connected to the router, for example webcams, keyboards, could get shared. Therefore a “binding” to an actual printer is required to prevent the situation like someone installed a webcam on your router and started peeking at you thousands of miles away…

TP-LINK’s solution requires additional software that is not a printer’s driver to be installed on the computer, which sucks. Well you can see what kind of person I am… I prefer everything to be clean… I turned to some opensource solutions such as DD-WRT and OpenWrt for clues, and soon I found something on DD-WRT’s website.

It was totally a surprise to me when I found that DD-WRT is supported on my TL-WR1043ND. The router is equipped with an Atheros 400 MHz CPU, 32MB of RAM, and a 8-MB flash. It is quite impressive that a wireless router could actually have a better hardware configuration than a PC back in around 1997. DD-WRT says it supports USB printer sharing, using a printer daemon called p910nd. After verified the hardware compatibility of the router with the firmware, I flashed DD-WRT to the router and gave the printer feature a try. It became a nightmare for me…

I thought it would be that easy: hook up the printer, enable the printer sharing feature, install drivers for printers through TCP port 9100 with the router’s IP, and done. It was nothing like that. After I went through all the steps according to various DD-WRT documentations, I came to the conclusion that this was simply not possible.

The problem was actually not the p910nd printer server, but the driver provided by Canon instead. What p910nd does is basically to convert the raw communication with the printer (via USB, of course) into a standard TCP/IP printing protocol used by all electronic devices. Most USB printers use the same printer driver as network printers, so the driver software will be able to communicate with the printer via a TCP port. However, Canon developed something on its own, called CAPT (Canon Advanced Printing Technology), which simply won’t respond to any data transferred from a TCP port, but keep complaining that the port is not supported instead. Screw you Canon! You screwed my weekend entirely up!

I once thought that it was no longer possible to use the router to share the printer, until I saw something called the USB/IP project. It is, of course, an open source project, hosted on sourceforge.net, and thus is very easy to get access to. The USB/IP project proposes exactly the same concept which I believe TP-LINK utilizes. How to resolve compatibility problem once and for all? Implement solutions from the lowest level! For example, virtual machines: if you can emulate an x86 processor and x86 operating systems on a Linux cloud, do you still expect anyone to report compatibility issues? The answer is, … Okay I stop. Let’s move on.

USB/IP provides a very elegant solution from bottom up — it encapsulates USB raw data, packet by packet, convert them into standardized TCP/IP packets, transfer them through the network, “unpacking” them on the other side, and emulates the results as if it came right from a USB port. It’s also a server — client system, so some driver still needs to be installed on the client side to “unpack” the encapsulated data and emulate a USB device. However, it’s open source and is fairly small — less than 200KB, so I’m okay with that, totally.

To install USB/IP server on a WR1043ND router requires OpenWrt, but not DD-WRT. DD-WRT is such a typically failed open source project which has probably the most confusing documentations in this universe. Besides, DD-WRT uses a very very simple, very very naive Linux kernel, and what’s worse, it pretends to be able to do everything — it does not give out warnings or errors when asked to do something it literally can’t, because the error prompting module is also dropped to save some space… Absurd, huh? Of course DD-WRT comes with its strengths, the web GUI is among one of them. But if you want to turn your router into some super server, which they actually deserve to be, you’ve got to use OpenWrt.

Unfortunately, documentation seems to be a intrinsic grief source for open source software. You can never install OpenWrt onto WR1043ND correctly if you follow what they say on their website… You should directly go to the download site, find a repository called “attitude-adjustment”, and locate the corresponding package by hardware. BE SURE to download the “squashfs” version but not the “jffs” version, and also be sure to choose “ar71xx” as the CPU type. Although both Broadcom and Atheros CPUs implement MIPS architecture, we cannot expect the same set of software to be working as they may do in the case of Intel and AMD. Just in case, I provide the links here if you want to skip the tedious searching step. It’s not that tedious by the way, you will find all kinds of interesting stuff all way along.

If you are upgrading from FACTORY firmware, click this.

If you are upgrading from an EXISTING OpenWrt firmware, or you finished installing the factory-to-openwrt firmware above, click this.

Flashing the firmware into the router is quite easy, yet risky. Just pay attention and you will be okay. You may want to check with your neighbors to make sure that they are not doing anything funny which would cause the power to go out without warning. Losing power when you are flashing the router is a disaster… If it happened, pick up your phone to call TP-LINK customer service, or prepare yourself with screwdrivers so that you can open your router right after… Hope that won’t happen. Okay, if all goes well, you just need to log in to you router’s web UI via a CABLE connection. Yes! You must connect to your router via a CABLE connection! Not wireless! Wireless sucks when you are trying to do serious things like this. Choose firmware upgrade option, which is usually listed under “system” or “administration tools”, and choose the corresponding firmware. If you are upgrading from an existing installation of OpenWrt, it’s pretty much the same, just watch out for a different version of firmware (note that the size is much smaller). While in progress, please please be patient. It could take up to 5 minutes for the router to reboot for the first time, so do not disconnect power or do anything else which you might regret doing. Again, if anything goes wrong at this stage… get your phone or get the tools, you know the drill. Again, hope that won’t happen.

If everything goes fine, your router should restart successfully and you will be able to access the router via its “ugly” web GUI. Yes, OpenWrt is not famous for its web GUI, it’s a barely functional interface only, without fillers, without decorations either. Now try to find the option to enable WiFi and SSH. Yes, you will need to manually enable WiFi after the installation, that why you must use a cable connection to flash it. As for SSH, just Google it and you will get way better results than what I can tell you here. After these steps, including setting up a new password for the router as prompted, you will be able to access the router via SSH protocol and control the router via the very basic, yet powerful, standard UNIX interface. If you are using Linux or OSX, simply type in

ssh [email protected]

and enter password as prompted. If you are using Windows, there is a software (also free and open source) called PuTTY which essentially does the same thing through the same command. After logging in, you will be with the familiar UNIX interface, where you can literally do anything as if you have a computer at your finger tips (actually you do have…). Just be reminded that your router only has a flash memory of 8MB, so watch out for the size of software packages. Now we will be installing the USB/IP server to the router. First run

opkg update

and then

opkg install usbip

The system should resolve all dependence and install required packages automatically for you. Double check that package kmod-usb-core is installed, or simply manually run

opkg install kmod-usb-core

just in case. Obviously you need basic USB support to get things work. Restart the router by typing

reboot

and hit return. Now you can do everything via wireless because the router is on its own now — it’s a fully functional computer! After the reboot, ssh to the router again, and use the following command to see if the printer is successfully detected. Oh yes, make sure to connect the USB cable of course. I think everybody is good at physics 🙂

lsusb

If you can’t find your printer, double check everything and make sure the printer is powered on. Usually it will only display the manufacturer of the printer (in my case it’s “Canon Inc.”), just make sure you are not skipping it. The command should also display on which bus the device is connected to. Usually it should be USB bus “1-1”. Please note that the entire thing is “bus” number and has nothing to do with device number. Different devices can be connected on the same bus and that’s why it is called “bus” literally (and literally). Take this number down, and we will be using it soon. Now call a command as follows to check what device are available for USB/IP

usbip list -l

If you see the bus number you’ve just taken down, then you are all set and you can move forward. If not… Debugging always sucks, but that’s life. You can try to enable the debugging mode of usbip to get more information. Google that for details.

The final step you will do with the router is to bind the printer to the USB/IP service. Simply use the following command

usbip bind -b 1-1

where 1-1 can be whichever bus your printer is connected to. It should tell you whether the operation is successful. Normally it should be successful, but there also exist thousands of reasons for it to go wrong… That’s life… Suck it up and do your best…

Forgive me for not telling you the truth… There is one more step… or two more. After you successfully bind the printer to USB/IP service, don’t forget to start the USB/IP server using command

usbipd &

Please note that the ampersand, which makes the process run in the background, is necessary, otherwise you will have to keep the ssh window open to make the server running. Make sure the system is listening on TCP port 3240 by typing the following command

netstat -an

and looking for an entry like “0.0.0.0:3240” in the upper part of the output. Perhaps you will need to configure your firewall to open this port to public. Go to the web GUI and you’ll find it fairly straightforward. It might also work if you leave the firewall with its default settings.

Now you’ve done all necessary steps on the router, so you can close the ssh window by crossing it off (brutally) or typing exit in the command line and hit return (gracefully). Now we will be configuring Windows on the client side. As for Linux and OSX, please find other articles or follow the guidelines at the USB/IP project homepage. I will try to create a tutorial for UNIX operation systems later, and it should be easier compared to Windows. The good thing about Windows is that people have compiled the driver for us and even “signed” them legally so that the driver can be conveniently installed into the system. Download the USB/IP client tool for Windows from this link. The latest version is 0.2 and just grab that one. Unzip the file, you will find one executable called usbip.exe, one INF file and a whole bunch of other fancy stuff. First, delete the executable usbip.exe. It just doesn’t work, I don’t know who compiled that… Anyway we install the driver first. Go to Computer, right click and choose Properties. Go to device manager on the right. Oh yes, I’m using Windows 7, and the driver works perfectly on 64-bit systems so don’t panic if you have a “super computer” at home. Click on any hardware node in device manager, then click Actions from menu, and choose Add legacy hardware. Choose install manually, and the device type is system device. Finally, when it asks for the driver for the device, choose “Have disk” and navigate to the unzipped folder. Actually all the steps are covered in a file in your unzipped folder called “USAGE”. Open that file with any text editor and you will see the instructions in a much more detailed manner. After installing, make sure you have a device called “USB/IP Emulator” under your “System Devices” node in your device manager. Now we can setup the client. Ahh… it can be painful, depending on which path you choose.

The first way — easy money: get the compiled client program from here. I modified the source code for you and compiled it using working settings. This executable works on x86 based Windows only. Don’t ask me for x64… There is no such thing as x64 actually, that’s x86-64 so you know it will work.

The second way — a little bit painful. It took me quite long (about 4 hours) to figure out what was wrong with the executable coming with the zip file. It was compiled using a older version of source code, and a very redundant “version check” feature on the server side caught the difference in version and terminated the connection. It remained a secret until I enabled the debugging mode on the server side, so that’s huge grief for me before I could locate the problem. The easiest way to fix this is to modify the version number defined in the source code and compile it manually. Download source code from here. Be sure to use the “Download GNU tarball” near the bottom… Unzip the file, and locate the file “usbip_protocol.h”. Open it with any text editor other than system notepad (which messes line-breaks up), and look for a line saying

#define USBIP_VERSION 0x000106

at the very beginning of the file. Change “0x000106” to “0x000111”, save and close the file. Open “usbip.sln” using Visual Studio. If you don’t have one installed you can use some computer at school… I myself used a CAEN computer to compile this file. Make sure to choose build mode to “Release” rather than “Debug”, and build the non-driver part only. Visual Studio has a very powerful compiler and it will optimize the final executable into around 70KB in size, which can be found in the newly created “Release” folder. Okay, that new usbip.exe is what you need! Copy that to your original folder for the USB/IP binaries and we are ready to go.

Be sure, be sure, and be sure that you do not have Daemon Tools virtual CD drive installed in your system. If you do, uninstall that! Somehow it is in conflict with the USB/IP driver. If you do need a virtual CD drive, I personally recommend a freeware called “Virtual Clone Drive”, which emulates CD/DVD/BD ROMs as perfectly as DT does, and uses way fewer system resources. Just a personal recommendation, and I’m not receiving any single bit of advertising revenue for saying that…

Open the Windows command console at your USB/IP binary folder. Right click inside the Windows Explorer holding “Shift” key will help a lot 🙂 Run command

usbip -l 192.168.1.1

to see if any device is ready. Of course, 192.168.1.1 can be change to any address to which your router is designated. If you found the USB bus number you are interested in, say 1-1 in previous examples, go attach it to your own computer by invoking

usbip -a 192.168.1.1 1-1

You know which can be modified and which can not, so I won’t repeat. If everything goes fine, you would see the program telling you

new usb device attached to usbvbus port #

where “#” is a designated port number, which is often 1 when you only have one device. Meanwhile you should hear a Windows notification sound indicating a new hardware and you can see Windows trying to install driver for the new device. From now on just treat the new device as a physically connected USB device and install drivers as you usually do. After all the necessary configurations steps your device will be ready to use.

Final note: please detach your device using the following command in a NEW command window:

usbip -d #

where “#” is the attached port number you get from your earlier invocation of usbip.exe. Also, do not close the command window when the device is not detached using the command above — this could prevent others from connecting to the device and you would probably have to reboot and reconfigure on the router side (bind bus, start the daemon, etc.) to make things work again. There is huge room for improvement, obviously, especially in terms of user-friendliness.

Anyway, this works, and this concludes the first detailed tutorial on the server/client side of the USB/IP project. It is a great project and it brings us huge convenience and saves us a lot of money from buying a network printer. Of course USB/IP is very powerful, it can attach any kind of USB device remotely directly to your computer, say a webcam. So if you feel uncomfortable of its implementation… Just check the wires to make sure that the printer is the only device connected to your router.

Oh yes, if you are using USB/IP service from WAN, or Internet, then security is a huge problem. The communication part of this software is not encrypted at all, so it may cause huge security problems when using sensitive devices like flash drives containing personal information, or even worse, eTokens for financial transaction authentications. The USB/IP project literally moves one of your internal system bus openly to the Internet, allowing everybody to see how pretty your girlfriend looks like. Therefore, if possible, the developer should, and must consider adding strong encryption to its communication layer. For now, it is strongly recommended only to enable USB/IP locally in LAN, but not in WAN. If you want to use the service from a remote host, use OpenVPN or similar tunneling technologies with unbreakable industrial-standard encryption schemes (preferably IPSec, PPTP’s MPPE is not strong enough to protect data supposed to be transferred using a “internal bus”) to connect to the target LAN and use the service.

Technology serves people, but you should always assume that someone is trying to screw you up.