Modem HOWTO: mobile broadband, serial devices and dial-up today

Updated November 2026

On a Linux system today, "modem" almost always means a cellular (LTE or 5G) module, managed by ModemManager and NetworkManager. Below that sits the plain serial port, which you still meet with USB serial adapters, microcontroller boards and the occasional analog modem. This page covers all three, with the commands to check that each one works.

The classic Modem-HOWTO (last revised in 2007) and Serial-HOWTO (last revised in 2011) are kept by the Linux Documentation Project at tldp.org. They describe IRQ jumpers, setserial and ISA cards. This page is written for current hardware and current distributions.

Which kind of modem do you have?

Modem types you are likely to meet, as of November 2026
TypeTypical device nodesHandled by
USB or M.2 cellular module (QMI or MBIM)/dev/cdc-wdm0, a wwan0 network interface, extra ttyUSB portsModemManager + NetworkManager
PCIe cellular module (newer laptops)/dev/wwan0mbim0, /dev/wwan0at0, wwan0Kernel WWAN subsystem (since Linux 5.13) + ModemManager
AT-command serial modem (RS-232 or USB)/dev/ttyS0, /dev/ttyUSB0, /dev/ttyACM0ModemManager (AT control, PPP data) or pppd directly
USB serial adapter or board (not a modem)/dev/ttyUSB0, /dev/ttyACM0A terminal program such as picocom

A single USB modem often exposes several ports at once: a control port, a network interface and one or more serial ports for AT commands or GPS. ModemManager groups them into one modem object. Some USB modems first appear as a USB disk holding Windows drivers; the usb-modeswitch package switches them into modem mode automatically.

Old "Winmodems" (software modems that leave the signal processing to a Windows driver) were the big problem of the dial-up era. They are now rare, and most never had free Linux drivers. If you need dial-up, buy an external modem that speaks AT commands; USB models usually appear as /dev/ttyACM0.

Mobile broadband with ModemManager

Install and check

Desktop installs of the major distributions normally ship ModemManager and NetworkManager. On a minimal or server install:

sudo apt install modemmanager network-manager      # Debian, Ubuntu
sudo dnf install ModemManager NetworkManager-wwan  # Fedora, RHEL, Alma, Rocky
sudo pacman -S modemmanager networkmanager         # Arch
sudo systemctl enable --now ModemManager

List the modems ModemManager has found, then show the details of one by its index:

mmcli -L
mmcli -m 0

The detail view shows the manufacturer and model, the firmware, the ports in use, the state (for example locked, disabled, registered or connected), signal quality, the operator and the SIM path. If mmcli -L lists nothing, run lsusb or lspci to check that the hardware is visible at all, and journalctl -u ModemManager -b for the reason.

Unlock the SIM

If the state is locked, the SIM wants its PIN. The SIM has its own index, shown in the modem details:

sudo mmcli -i 0 --pin=1234

Count your attempts. Three wrong PINs usually lock the SIM until you enter the PUK from the carrier. Check the PIN before scripting this.

ModemManager only talks to the modem: it registers on the network and opens a data "bearer". It does not configure IP addresses on the host. NetworkManager reads the IP settings from the bearer and applies them, so the normal way to get online is a NetworkManager connection profile:

sudo nmcli connection add type gsm con-name mobile gsm.apn internet
sudo nmcli connection up mobile

Replace internet with your carrier's APN (access point name). Add gsm.username, gsm.password and gsm.pin if your carrier or SIM needs them. The profile needs no interface name; without one, NetworkManager uses it for whichever modem is present, which is simpler because modem interface names can change. With gsm.auto-config yes, NetworkManager takes the APN and login from the mobile broadband provider database instead (see nm-settings-nmcli(5)).

Check the result:

nmcli device status
mmcli -m 0          # state should now be "connected"
mmcli -b 0          # bearer: IP method, address, DNS, MTU
ip addr show wwan0

Useful mmcli commands

sudo mmcli -m 0 --enable
mmcli -m 0 --signal-setup=30        # refresh signal figures every 30 s
mmcli -m 0 --signal-get             # RSSI, RSRP, RSRQ, SNR
sudo mmcli -m 0 --3gpp-scan --timeout=300
mmcli -m 0 --messaging-list-sms
sudo mmcli -m 0 --messaging-create-sms="text='Hello',number='+15551234567'"
sudo mmcli -s 0 --send              # send SMS number 0 from the list
sudo mmcli -m 0 --location-enable-gps-nmea
sudo mmcli -m 0 --location-get
sudo mmcli -m 0 --simple-disconnect

mmcli -m 0 --simple-connect="apn=internet" also exists. It opens the bearer but leaves the IP setup to you, which makes it a testing tool rather than a way to get online.

Laptop modules that refuse to go online

Some WWAN modules shipped by Lenovo, Dell and HP have an "FCC lock": they stay in low-power mode until a vendor-specific unlock command is sent. Since ModemManager 1.18.4 the unlock scripts are installed but not active. They live in /usr/share/ModemManager/fcc-unlock.available.d/, named by USB or PCI vid:pid. Read the ModemManager FCC unlock page first, then enable the one for your module at your own responsibility:

lspci -nn | grep -i -e wwan -e modem      # or lsusb, to find vid:pid
sudo ln -sft /etc/ModemManager/fcc-unlock.d \
  /usr/share/ModemManager/fcc-unlock.available.d/105b:e0ab
sudo systemctl restart ModemManager

The scripts call qmicli or mbimcli, from the libqmi-utils and libmbim-utils packages on Debian and Ubuntu.

Serial devices

Names and permissions

Built-in UARTs are /dev/ttyS0 and up. USB serial adapters with a vendor chip (FTDI, Prolific, CH340, CP210x) appear as /dev/ttyUSB0; devices that follow the USB CDC-ACM standard (many microcontroller boards and modems) appear as /dev/ttyACM0. The numbers depend on plug-in order, so use the stable links udev creates:

ls -l /dev/serial/by-id/
sudo dmesg | grep -i tty          # which driver claimed the device

Serial devices are not world-writable. The default udev rules from systemd give them the group dialout; Arch Linux patches this to uucp. Check, then add yourself to whatever group the device shows:

ls -l /dev/ttyUSB0
# crw-rw---- 1 root dialout 188, 0 ... /dev/ttyUSB0
sudo usermod -aG dialout "$USER"   # Arch: sudo usermod -aG uucp "$USER"

Log out and in again for the new group to apply. Running the terminal program with sudo works too, but it is a bad habit.

Talk to the device

picocom is small and needs no configuration file:

sudo apt install picocom           # or dnf / pacman
picocom -b 115200 /dev/ttyUSB0
picocom -b 115200 -f h /dev/ttyS0  # with RTS/CTS hardware flow control

Leave picocom with Ctrl-a then Ctrl-x. For an AT modem, type AT and Enter; the answer should be OK. ATI usually prints the model. minicom (minicom -D /dev/ttyUSB0 -b 115200) and screen /dev/ttyUSB0 115200 do the same job. To set port parameters without a terminal program, use stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb.

Stop ModemManager from probing your board

Under its default "strict" filter policy, ModemManager probes a generic tty only when it is fairly sure the device is a modem. If it still grabs a board (you see AT commands arriving, or a device that resets on plug-in), tag the device so ModemManager ignores it. Find the IDs with udevadm info -a /dev/ttyACM0, then create /etc/udev/rules.d/79-mm-ignore-myboard.rules:

ACTION!="add|change|move|bind", GOTO="mm_myboard_end"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", ENV{ID_MM_DEVICE_IGNORE}="1"
LABEL="mm_myboard_end"
sudo udevadm control --reload
sudo udevadm trigger

Use your board's own vendor and product IDs; the ones above are only an example. Unplug and replug the device afterwards.

Dial-up, briefly

Analog dial-up still exists for out-of-band access to remote sites and for a few rural users. ModemManager and NetworkManager can drive an AT modem and run PPP over it. Without them, pppd with a chat script does the job: a peers file sets the device and options, and the chat script dials. The full set-up, including the secrets files and debugging, is on the PPP HOWTO page. A minimal chat script, /etc/chatscripts/dialup, looks like this:

ABORT BUSY
ABORT 'NO CARRIER'
'' ATZ
OK ATDT5551234
CONNECT ''

Troubleshooting checklist

Sources