Cell: modems over libusb

Added: 2026-10

Quectel cell modems present their AT, DIAG, and NMEA ports as vendor-specific USB serial interfaces. Linux binds them to the option driver and creates /dev/ttyUSB* ports, but macOS has no host driver for them: no /dev/cu.* ports appear when the modem is plugged in.

The cell AT and cell DIAG sources instead talk to the modem’s interfaces directly over libusb, so these modems work on macOS with no driver or kernel extension.

The libusb method works on Linux as well. It is used automatically for a supported modem which no driver has claimed (for instance when the option driver isn’t loaded, or doesn’t know the modem’s USB ID), and usb=force uses it even when the option driver has bound the modem. This can be useful on a system where the serial driver is missing or misbehaves, or to avoid depending on /dev/ttyUSB* numbering.

Supported modems

ModemUSB ID
Quectel EC212c7c:0121
Quectel EC25 / EG25-G2c7c:0125
Quectel EG912c7c:0191
Quectel EG952c7c:0195
Quectel BG962c7c:0296
Quectel EP06 / EG06 / EM062c7c:0306
Quectel EG12 / EM12 / EG182c7c:0512
Quectel RM500Q / RM502Q2c7c:0800
Quectel RM520N2c7c:0801

The interfaces are given their roles from Quectel’s usual layout. On the EG25-G, for instance:

InterfaceRole
0DIAG
1NMEA (GNSS)
2AT
3modem (also answers AT)
4QMI / RmNet; not a serial port, and not used

Which of these modems the cell sources can survey is listed under the cell AT supported hardware.

USB port names

A modem interface reached over libusb is named usb:<bus>-<addr>:<interface> anywhere a serial port path would be used. On macOS the bus is numbered from 0, so a name may look like usb:0-3:2; on Linux buses are numbered from 1, matching lsusb, such as usb:1-4:2.

The port scan of both cell sources includes these interfaces, --list shows the modems found this way, and the atport=, diagport=, and gpsport= options accept them:

$ kismet -c cellat-<imei>
$ kismet -c 'celldiag-<imei>:atport=usb:0-3:2,diagport=usb:0-3:0'

The bus address changes when the modem re-enumerates (when it is re-plugged or reboots), so a usb: name is only good for one session. The IMEI in the source name stays the same, so normally there is no need to name the ports.

The usb= option

Both cell sources take a usb= option:

  • usb=auto (default): use the interfaces of supported modems which no host driver has claimed. On macOS this is every supported modem; on Linux it is a modem the option driver hasn’t bound.
  • usb=force: also take interfaces away from their host driver (such as option or qcserial on Linux) while the source runs. The driver gets them back when the source closes.
  • usb=off: don’t use libusb.

Behavior

  • Each source claims only the interface it uses, so a cell AT source and a cell DIAG source can share one modem. An interface claimed by another process is treated as busy, the same as a serial port another process holds.
  • When the modem is unplugged, the source reports that the device was removed.
  • The Qualcomm DIAG interface on the EG25-G accepts only one HDLC frame per USB transfer, and drops the rest of the transfer; the libusb support splits DIAG writes into one frame per transfer.

kismet_usbserial

kismet_usbserial serves the serial interfaces of a supported modem as pseudo-terminals, on macOS or Linux, so other serial tools (a terminal program, minicom, a GNSS tool reading NMEA) can open the modem like any tty. It takes interfaces away from a host driver while it runs.

$ kismet_usbserial --list
2c7c:0125 bus 0 addr 3  Quectel EC25 / EG25-G

$ kismet_usbserial --link-dir /tmp
Quectel EC25 / EG25-G
  diag   interface 0  /dev/ttys004  /tmp/modem-diag
  nmea   interface 1  /dev/ttys005  /tmp/modem-nmea
  at     interface 2  /dev/ttys006  /tmp/modem-at
  modem  interface 3  /dev/ttys007  /tmp/modem-modem
Option
--listlist the supported modems which are attached
--device VID:PIDthe modem to open, by USB ID in hex (default: the first supported modem)
--usb BUS:ADDRthe modem to open, by USB bus and address
--link-dir DIRmake symlinks DIR/PREFIX-ROLE to each port’s pty
--link-prefix PREFIXthe symlink name prefix (default: modem)
--verbosereport traffic counts

kismet_usbserial claims every serial interface of the modem, so the Kismet cell sources can’t reach it over libusb while it runs; stop it before using the modem in Kismet.

Compiling

libusb support for the cell modems, and kismet_usbserial, are built by default when libusb-1.0 is found. They can be disabled by passing --disable-usbserial to ./configure. Without it, the cell sources still work with modems which have host serial ports.

Permissions

On Linux, using a modem over libusb needs write access to its USB device (under /dev/bus/usb/); run the capture as root, or grant access to the device with a udev rule. The Kismet packages install a rule which gives the kismet group access to Quectel modems:

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="2c7c", MODE="0660", GROUP="kismet"

Taking an interface from its driver with usb=force needs no additional permission beyond access to the USB device.