Windows & DOS Community

Use a rooted Android smartphone as a "serial modem" with DOS

Post Reply   Page 1 of 1  [ 2 posts ]
Author Message
Post subject: Use a rooted Android smartphone as a "serial modem" with DOS
Posted: 27 Nov 2022 14:04
Membre inscrit
User avatar
Posts: 69
Joined: 28 Mar 2022 21:17
Hello! :wave: Several months ago, I had this crazy idea to "tether" my PC to my smartphone when running DOS, using a serial null-modem. Eventually I got it working, so I'd like to share what I did, in case anybody else might find it interesting! My starting point was this, but I had to make a lot of adjustments due to running on Android.

Materials required

To get this "tethering" setup working, you will need:
  • A PC with a serial port running DOS
  • The epppd packet driver (it comes with, e.g., Arachne)
  • A serial null-modem cable
  • A USB-C to serial adapter (or whatever type of USB port your phone has) – this is the one I'm using: ... rd_w=p3Aah
  • A rooted Android (preferably LineageOS) smartphone (I guess it would be easier on a Librem, and conversely impossible on an iPhone!), running a kernel to which one of the following applies:
    • The kernel has built-in support for your serial adapter (unlikely I'd say…)
    • The kernel supports modules so you can build the module for your serial adapter and insmod it (that's what I had to do)
    • You can flash your own kernel, after building one with the serial adapter driver built in
  • Termux with the tsu package installed (pkg install tsu)
Checking the kernel

Before investing any time or money in this project (assuming you're starting with a rooted phone), you can check if your kernel satisfies one of the conditions listed above. To check if it has built-in support for the serial adapter, you can run this command from Termux (you may need to "pkg install gzip" first):
sudo zgrep CONFIG_USB_SERIAL_ /proc/config.gz
If it tells you there is no such file or directory, then unfortunately these checks can't be performed. If you get a bunch of lines ending in "=y", then your kernel is fine, and you can skip the rest of this section and the next. If you get "is not set", then that means the support is not built-in.

If the support is not built-in, the next step is to check if your kernel has module support:
sudo zgrep CONFIG_MODULES /proc/config.gz
If you get "CONFIG_MODULES=y", then modules are supported, and you can build the one for your serial adapter. This requires patience, but shouldn't be intractible.

If CONFIG_MODULES is "n" or "not set", then you'll have to build a new kernel and flash it. Again, this requires patience, and (depending on your device) may be impossible :(
I don't have any experience of doing this, so I can't really advise on how to proceed…

Compiling the kernel module

I'm going to recount here what I did, even though I'm almost certain that there are better ways. It's very hard to find tutorials on this, and any I could find seemed to be out of date. If anyone has any better methods, please suggest them and I'll update the tutorial!

To compile a kernel module you need to get the kernel source, adjust the config file, and compile it. Given my experience compiling Linux kernels for PCs, I expected this to be straightforward, but in the Android ecosystem everything seems to be extra-complicated… Unfortunately all I can talk about is my own experience, which is with LineageOS on a FairPhone 3.

Basically I followed the instructions for building LineageOS, as far as running "./". (If you're running LineageOS on something other than FP3, you can find the equivalent instructions for your device on the same wiki. If you're running a different Android distribution, or the stock ROM for your device, again I'm unfortunately unsure as to the best course of action…) Then instead of doing "brunch FP3", I did the following:
sed 's/# CONFIG_USB_SERIAL_FTDI_SIO is not set/CONFIG_USB_SERIAL_FTDI_SIO=m/' -i kernel/fairphone/sdm632/arch/arm64/configs/lineageos_FP3_defconfig
mka kernel
Here, FTDI_SIO is the chip in that serial adapter I recommended. I think it's the same chip you'll find in most adapters sold today, but there are other chips you can build drivers for if needed. The path and name of the defconfig file will obviously change if you are building for something other than the FairPhone 3.

The whole process takes ages, since it needs to sync up the entire Android source tree. It is highly wasteful since we only want to compile a little module, but it's the only way I could make it work. Again, if anybody has any better instructions, please post them and I'll happily update the tutorial!

Anyway, at the end of this I had a file "out/target/product/FP3/obj/KERNEL_OBJ/drivers/usb/serial/ftdi_sio.ko" (again replace FP3 with your device). You can copy this ko file to your phone and place it in Termux's home directory. Once this ordeal is over, be sure not to delete anything – you'll need to resync the source and recompile the kernel if any OTA update makes a breaking change!

Setting up Termux scripts

Once you have the kernel module handy (if needed), you can get onto the fun stuff – actually setting up the null modem link from the phone side. All commands in this section are to be run on your phone in the Termux terminal. You can create the scripts as follows:
cat > <<EOF
cd /data/data/com.termux/files/home

# Install the kernel module if needed
lsmod|grep ftdi || insmod ftdi_sio.ko

# Verify the yoke is plugged in
stat /dev/ttyUSB0 || exit "Looks like the serial adapter is not plugged in!"

# Setup the actual connection
# Based on
# No lock since Android doesn't have "/var/lock" as a location
proot -b ppp_scripts:/etc/ppp pppd ttyUSB0 115200 local debug noccp passive proxyarp defaultroute noauth mtu 1500

mkdir -p ppp_scripts
cat > ppp_scripts/ip-down <<EOF

# Clean up the firewall and routing stuff
ROUTETABLE=$(/data/data/com.termux/files/usr/bin/ip route get $IPREMOTE | grep table | sed 's/.*table \([0-9]*\) .*/\1/')
UPSTREAM=$(/data/data/com.termux/files/usr/bin/ip rule | grep "from all iif lo oif [^ ]* lookup $ROUTETABLE" | sed 's/.*oif \([^ ]*\).*/\1/')
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $UPSTREAM -o $IFNAME -m state --state RELATED,ESTABLISHED -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $IFNAME -o $UPSTREAM -m state --state INVALID -j DROP
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $IFNAME -o $UPSTREAM -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_counters -i $IFNAME -o $UPSTREAM -j RETURN
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_counters -i $UPSTREAM -o $IFNAME -j RETURN

/data/data/com.termux/files/usr/bin/ip rule del from all iif $IFNAME lookup $ROUTETABLE
/data/data/com.termux/files/usr/bin/ip rule del to $IPREMOTE lookup $ROUTETABLE

cat > ppp_scripts/ip-up <<EOF

# This will resolve to "ip route add $IPREMOTE <BLAH> table <CORRECTNUMBER>"
ROUTETABLE=$(/data/data/com.termux/files/usr/bin/ip route get $IPREMOTE | grep table | sed 's/.*table \([0-9]*\) .*/\1/')
/data/data/com.termux/files/usr/bin/ip route add $(/data/data/com.termux/files/usr/bin/ip route|grep $IPREMOTE) table $ROUTETABLE

# Set up the appropriate forwarding rules in the firewall
UPSTREAM=$(/data/data/com.termux/files/usr/bin/ip rule | grep "from all iif lo oif [^ ]* lookup $ROUTETABLE" | sed 's/.*oif \([^ ]*\).*/\1/')
/data/data/com.termux/files/usr/bin/iptables -t nat -A tetherctrl_nat_POSTROUTING -o $UPSTREAM -j MASQUERADE
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -j bw_global_alert || true # Remove it if it's already there so we don't duplicate it…
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 1 -j bw_global_alert
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 2 -i $UPSTREAM -o $IFNAME -m state --state RELATED,ESTABLISHED -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 3 -i $IFNAME -o $UPSTREAM -m state --state INVALID -j DROP
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 4 -i $IFNAME -o $UPSTREAM -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -A tetherctrl_counters -i $IFNAME -o $UPSTREAM -j RETURN
/data/data/com.termux/files/usr/bin/iptables -A tetherctrl_counters -i $UPSTREAM -o $IFNAME -j RETURN

# And finally make sure that packets get routed properly from/to the client
RULEPRIO=$(/data/data/com.termux/files/usr/bin/ip rule | grep -m 1 "from all iif [^ ]* lookup $ROUTETABLE" | sed 's/^\([0-9]*\):.*/\1/')
/data/data/com.termux/files/usr/bin/ip rule add from all iif $IFNAME lookup $ROUTETABLE priority $RULEPRIO
/data/data/com.termux/files/usr/bin/ip rule add to $IPREMOTE lookup $ROUTETABLE priority $RULEPRIO
Again, there may be some LineageOS-specific stuff in here, I'm not sure how well these scripts will work on other Android distributions…

If your kernel has the support for the serial adapter built-in (i.e. you don't need the module) then remove the lsmod/insmod line in "~/". You can also install the Termux:Widget app and create a friendly wrapper script:
cat > ~/.shortcuts/Setup\ Null\ Modem <<EOF
sudo ~/
To make sure all these scripts work, you'll need to install some packages:
pkg install termux-tools iptables iproute2
All going well, it should be possible to plug in the serial adapter to your phone's USB port, and run the "Setup Null Modem" script from the Termux widget on your home screen, and it will start listening on the serial port for PPP connections. Once a device on the other end of the null-modem (i.e. your DOS PC) makes this connection, pppd will establish an IP link where the phone has address and the DOS PC has address (if these addresses are unsuitable for some reason, you can change them in ~/ – you can also change the baud rate from 115200 to something lower, and the MTU from 1500 to something lower, if needed). Once this link is set up, it will run the script ~/ppp_scripts/ip-up, which does the following:
  • Finds the ip routing table for Android's current default network connection (e.g. WiFi) and adds an entry that tells it to send any packets destined for over the PPP link (instead of trying to send them over WiFi). Note that because of the hacky way I've done this, the link will probably stop working if you switch between WiFi and mobile data, or enable/disable a VPN, while the connection is up…
  • Adds a "masquerade" iptables entry, so that any packets originating from the DOS PC are "masqueraded" as coming from the phone itself, when they are sent out to the external network.
  • Adds several iptables entries to the "tetherctrl" chains, to ensure that packets to/from the DOS PC are routed through instead of being dropped.
  • Adds some "rules" to the kernel's list to make sure that the correct routing tables are looked up for packets coming from the DOS PC can be sent to the external network, and that any packets coming in response are routed back to the DOS PC. Without this, you'd get "Destination Net Unreachable" errors…
You can take down the link by simply unplugging the serial adapter. Then pppd will run ~/ppp_scripts/ip-down, which reverses all the configuration changes made by ip-up, and then shut itself down.

Connecting the DOS PC

Once pppd is running on the phone, and the null-modem is connected to the DOS PC's serial port, you can start epppd from the DOS prompt:
epppd com1 115200
If you changed the baud rate in the pppd invocation on the phone, change it here too. Obviously change com1 to a different port if needed, also. All going well, it should install the packet driver at vector 0x60, and you'll have a working network connection! If you're using wattcp-based programs, e.g. Lynx, you can put the following in your wattcp.cfg file:
Change your "nameserver" if needed, this is what it is for me. You can use your WiFi router, or the servers provided by your ISP. If you're not sure what to use, there are some free public ones suggested here. The configuration for Arachne should be similar.

If running Windows 3.1 (like me), you can also install Trumpet. One way to use it is to run "winpkt 0x60" after starting epppd, then start Windows. You can then configure Trumpet with the IP and DNS settings given above. I use Trumpet 2.0 (rather than the 3.0 offered here) since it doesn't impose a 30-day trial period. Apparently it is still possible to "register" the newer versions to support the author financially, but I have not succeeded in getting a registration code by doing so :?

It is also possible (and seems to work a bit better) to bypass epppd by using Trumpet's "Internal PPP", which involves a few different settings. In this case, you don't run epppd at all, but just start Windows. My settings currently look something like this (again, change your "Name server" if needed):
My Trumpet settings, with only relevant fields filled in
But either way, it's unfortunately quite dodgy. Attempting to download a file from from any Windows-based browser seems to lock up the entire connection, while downloading files using Lynx from DOS doesn't cause any problems. I'm not sure if this can be overcome with the correct choice of MTU/MSS/RWIN – again, any guidance would be welcome!

Setting up a HTTP Proxy

Now that you've got Windows 3.1 accessing the internet through your phone, you may wish to set up a WebOne instance on the latter, so that the former can access more of the modern web. To do this, you will need proot-distro, which allows you to install a Linux distro within Termux. I used Debian for this, though admittedly Ubuntu might have been a bit more straightforward.

Basically, I did this:
pkg install daemonize
pkg install proot-distro
proot-distro install debian
cd ../usr/var/lib/proot-distro/installed-rootfs/debian/root/
wget	# May need to change depending on the version of Debian you have installed
proot-distro login debian
dpkg -i packages-microsoft-prod.deb
apt update
apt install ./webone.0.14.0.linux-amd64.deb
You may start getting warnings about how systemd isn't running, but these seem to be harmless.

Then you need to add this to the end of ~/ppp_scripts/ip-up:
# Setup our HTTP proxy
daemonize /data/data/com.termux/files/usr/bin/proot-distro login debian -- webone --daemon
And this to the end of ~/ppp_scripts/ip-down:
# Shut down HTTP proxy
killall webone
Then you can configure your browser under Windows 3.1 to use port 8080 as its proxy server! :)


So there you have it! It is possible, with a bit of patience and hacking, to use a modern smartphone as a serial modem and connect DOS to the internet over WiFi/mobile! Naturally, this being serial, the connection is very slow, but I guess that adds to the nostalgia factor. In fact, maybe a bit of tweaking to the PPP scripts (an ip-pre-up script?) could be used to make the phone play a recording of the traditional dial-up sound to complete the experience! :lol:

Any feedback welcome! :D (especially suggestions for improving the kernel module compilation and Trumpet settings…)

Profile Quote
Post subject: Re: Use a rooted Android smartphone as a "serial modem" with DOS
Posted: 18 Feb 2023 22:09
Membre inscrit
User avatar
Posts: 69
Joined: 28 Mar 2022 21:17
Apologies for the double-post, but I just want to note that I've updated the tutorial slightly with some more instructions for using Trumpet's Internal PPP, and instructions for setting up WebOne as part of the tethering!

Display: Sort by: Direction:
Post Reply   Page 1 of 1  [ 2 posts ]
Return to “Resources”
Jump to: