После того, как modemmanager опознал модем, остаётся только подключиться к сети указав правильные параметры подключения.
Проблема
Для получения доступа к интернету через модем, необходимо указать следующие параметры:
- Access Point Name (APN);
- User name;
- Password.
Указанные параметры можно получить разными способами:
- Запросить SMS с настройками у оператора;
- Задать вручную;
- Найти в базе данных настроек.
Первый способ, насколько я понимаю, не стандартизован, т.е. у каждого оператора этот способ будет работать по-разному, поэтому не особенно нас интересует.
Со вторым способом всё и так понятно, посмотрим на третий.
Добываем APN
Настройки APN будем добывать из базы apns-config.xml. Источников, откуда можно взять эту базу, существует множество, отличаются они друг от друга разной степенью полноты и разной актуальностью.
Наибольшее доверие вызывают следующие варианты:
- Вариант от google https://android.googlesource.com/device/sample/+/main/etc/apns-full-conf.xml ,
- Вариант от lineage os https://github.com/LineageOS/android_vendor_cm/blob/cm-14.1/prebuilt/common/etc/apns-conf.xml
Два этих варианта имеют большое количество различий: xmldiff показывает 3849 изменений по существу (не считая перестановки строк и удалённых комментариев). Для простоты возьмём вариант от google, и положим в свой git, чтобы вносить изменения: .
Достать интересующие нас параметры в bash можно с помощью утилиты типа xq, собственно первые версии скрипта использовали именно этот инструмент. Однако, будучи написанной на go, эта штука имеет большой размер (7.5 МБ для rv64), поэтому xq пришлось заменить на cxq.
Утилита cxq написана на Си, с помощью библиотеки libxml2, суммарный размер этой связки зависит от количества включенных в библиотеке фич, например в buildroot rv64 получается около 1.2 МБ.
XPath запрос для получения строки БД содержащей искомый APN будет выглядеть следующим образом:
$ apn=$(cxq -f apns-full-conf.xml -x /apns/apn[@mcc="${mcc}"][@mnc="${mnc}"] | grep "default" | head -n 1)
После того как APN строка получена, можно получить имя apn, user name и password:
apn_addr=$(echo ${apn} | cxq -x /apn/@apn)
apn_user=$(echo ${apn} | cxq -x /apn/@user)
apn_pwd=$(echo ${apn} | cxq -x /apn/@password)
TL;DR
В итоге, полный скрипт будет выглядеть следующим образом:
#!/bin/bash
TIMEOUT_USBDEV=20
TIMEOUT_MM=10
TIMEOUT_MMMODEM=20
TIMEOUT_OPID=10
TIMEOUT_PPPD=10
VIDPID_SIERRA_EM7455="1199:9071"
/etc/init.d/S44modem-manager restart
# Check if m.2 modem is present
ctr=0
while :; do
sleep 1
echo "Waiting for USB device"
if [ -n "$(lsusb | grep ${VIDPID_SIERRA_EM7455})" ]; then
echo "Found Sierra EM7455"
break;
fi
if [ ${ctr} -gt ${TIMEOUT_USBDEV} ]; then
echo "Error: Timeout while waiting for USB device: $(lsusb)"
exit 1
fi
ctr=$((++ctr))
done
ttyusb=$(ls /dev | grep ttyUSB | tail -n 1)
if [ -z ${ttyusb} ]; then
echo "Error: tty not found"
exit 2
fi
echo "Wait for ModemManager"
ctr=0
while [ $(ps ax | grep ModemManager | wc -l) -ne 2 ]; do
sleep 1
if [ ${ctr} -gt ${TIMEOUT_MM} ]; then
echo "Error: Timeout while waiting for ModemManager"
exit 3
fi
ctr=$((++ctr))
done
echo "Report tty modem ${ttyusb} to mm"
mmcli --report-kernel-event="action=add,subsystem=tty,name=${ttyusb}"
sleep 1
ctr=0
while [ "$(mmcli -L)" = "No modems were found" ]; do
sleep 1;
echo "retry: $(mmcli -L)";
if [ ${ctr} -gt ${TIMEOUT_MMMODEM} ]; then
echo "Error: Timeout while waiting for modem"
exit 4
fi
ctr=$((++ctr))
done
NR=$(mmcli -L | sed -e "s|^.*/Modem/\([0-9]\) .*$|\1|")
echo "Got modem id: ${NR}"
echo "Check SIM presence"
sim=$(mmcli -m ${NR} | grep SIM | wc -l)
if [ ${sim} -eq 0 ]; then
echo "Error: SIM is missing: $(mmcli -m ${NR})"
exit 5
fi
ctr=0
opid=""
while [ -z ${opid} ]; do
sleep 1;
mmcli -m ${NR} -e
mmcli -m ${NR} --3gpp-register-home
mmcli -m ${NR}
opid=$(mmcli -m ${NR} | grep "operator id" | sed -r "s/^[[:space:]]+\|[[:space:]]+operator id:[[:space:]]+([[:digit:]]+)[[:space:]]*$/\1/")
echo "Waiting for operator id"
if [ ${ctr} -gt ${TIMEOUT_MMMODEM} ]; then
echo "Error: Timeout while waiting for operator id"
exit 6
fi
ctr=$((++ctr))
done
echo "Obtained operator id: ${opid}"
mcc=$(echo ${opid} | cut -c -3)
mnc=$(echo ${opid} | cut -c 4-)
echo "mcc: ${mcc}, mnc: ${mnc}"
apn_addr=""
apn_user=""
apn_pwd=""
echo "Lookup operator in apn DB"
apn=$(cxq -f apns-full-conf.xml -x /apns/apn[@mcc="${mcc}"][@mnc="${mnc}"] | grep "default" | head -n 1)
echo "APN: ${apn}"
apn_addr=$(echo ${apn} | cxq -x /apn/@apn)
apn_user=$(echo ${apn} | cxq -x /apn/@user)
apn_pwd=$(echo ${apn} | cxq -x /apn/@password)
echo "apn addr: ${apn_addr}, apn user: ${apn_user}, apn password: ${apn_pwd}"
if [ -z "${apn_addr}" ]; then
echo "Error: APN addr not found"
fi
conn_str="apn=${apn_addr}"
if [ -n "${apn_user}" ]; then
conn_str="${conn_str},user=${apn_user}"
fi
echo "Connect to APN"
if [ -n "${apn_pwd}" ]; then
conn_str="${conn_str},password=${apn_pwd}"
fi
mmcli -m ${NR} --simple-connect="${conn_str}"
mmcli -m ${NR} --bearer 0
echo "Start pppd"
pppd &
ctr=0
while [ ! -e /etc/ppp/resolv.conf ]; do
sleep 1; sleep 1;
echo "Waiting for ppp connection"
if [ ${ctr} -gt ${TIMEOUT_PPPD} ]; then
echo "Error: Timeout while waiting for ppp connection"
exit 7
fi
ctr=$((++ctr))
done
cp /etc/ppp/resolv.conf /etc/resolv.conf
echo "Done"
Предполагается что:
- База APN лежит в той же директории;
- Конфигурация pppd (/etc/ppp/options) уже выполнениа
После всего этого модем должен быть подключен к сети с доступом в интернет, если он конечно оплачен =)