UMGUM.COM (лучше) 

Linux + ZTE MF180 + Nokia 3110c + автоподключение ( Настройка автоматического подключения к интернету в среде Linux для модемов "ZTE MF180" и "Nokia 3110c". )

13 июля 2012  (обновлено 15 августа 2016)

OS: Linux Debian Sqeeze.
Hard: "USB modem ZTE MF180" и мобильный телефон "Nokia 3110c".
Applications: bash, UDEV, ppp.

Задача: обеспечить автоматическое установление сессии PPP (соединение с сервером удалённого доступа провайдера интернет) при физическом подключении беспроводного модема с выбором профиля по идентификаторам оборудования.

Не так давно заимел я USB-"свисток" беспроводного модема "ZTE MF180" с симкой "K-Cell". Специально такое покупать не стал-бы, так как имеющийся на борту моего мобильного телефона модем меня вполне удовлетворяет, но "за так" - почему бы и нет? "Why not?", как говорится. В предыдущей заметке я рассказал о том, как вживлял модем "ZTE MF180" в рабочее окружение своего Linux.

Побаловался пару дней, но не более того. Применять на практике, в условиях командировки, на объекте в серверной с "отвалившимися" каналами связи, или просто на скамейке в парке, "ручное" подключение не особо удобно. Хотелось большей автоматизации. Созрела мысль настроить полностью автоматический выход в интернет мобильного компьютера, "нетбука" например, при физическом подключении устройства с беспроводным модемом на борту. У меня постоянно с собой мобильный GSM-телефон с "симкой" от "Bee-Line", в сумке с "нетбуком" прописался модем с "симкой" от "K-Cell" - нужно бы научить мой Linux распознавать, что ему подсунули и по созданным заранее профилям инициировать подключение к интернет. Чтобы просто воткнул один провод, и получил доступ в интернет через "K-Cell"; не понравилось - переткнулся на другой провод, получил доступ в интернет через "Bee-Line". Чтобы вообще без единого нажатия клавиши или движения "манипулятора типа мышь".


Как работать с "ZTE MF180" я уже рассказал здесь, повторяться не буду. Модем на борту мобильного телефона "Nokia 3110c" у меня корректно распознаётся уже лет пять, тут и говорить не о чём. Просто для представления о том, с чем имеем дело, показываю, какое у моего Linux ядро на данный момент:

# uname -a

Linux 2.6.32-5-amd64 x86_64 GNU/Linux

Беспроводной модем "ZTE MF180" распознаётся следующим образом:

# dmesg

....
usb 1-4: New USB device found, idVendor=19d2, idProduct=0031
....
usb 1-4: Product: ZTE WCDMA Technologies MSM
usb 1-4: Manufacturer: ZTE,Incorporated
....
USB Serial support registered for GSM modem (1-port)
option 1-4:1.0: GSM modem (1-port) converter detected
usb 1-4: GSM modem (1-port) converter now attached to ttyUSB0
option 1-4:1.1: GSM modem (1-port) converter detected
usb 1-4: GSM modem (1-port) converter now attached to ttyUSB1
option 1-4:1.3: GSM modem (1-port) converter detected
usb 1-4: GSM modem (1-port) converter now attached to ttyUSB2
usbcore: registered new interface driver option
option: v0.7.2:USB Driver for GSM modems
....

Мобильный телефон "Nokia 3110c" с модемом на борту распознаётся следующим образом:

....
usb 3-2: New USB device found, idVendor=0421, idProduct=005e
....
usb 3-2: Product: Nokia 3110c
....
cdc_acm 3-2:1.1: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters
....

Напишем правила UDEV, которые будут отлавливать события включения и отключения целевых устройств, запускать сторонний скрипт с передачей таковому условного имени профиля подключения и адреса интерфейса, на котором расположен модем:

# cat /etc/udev/rules.d/99-gsm-mobile-net.rules

# Внимание: строка "ATTRS{modalias}" содержит идентификаторы в верхнем регистре, в отличии от других мест, где они указываются в нижнем.

# Детектирование подключения "ZTE MF180"
SUBSYSTEMS=="usb", KERNEL=="ttyUSB*", ACTION=="add", ATTRS{modalias}=="usb:v19D2p0031*", ATTRS{bInterfaceNumber}=="03", ATTRS{bInterfaceProtocol}=="ff", RUN+="/usr/local/bin/ppp-gsm-custom.sh zte-mf180 add $kernel"

# Детектирование отключения "ZTE MF180"
SUBSYSTEMS=="usb", KERNEL=="ttyUSB*", ACTION=="remove", ATTRS{idVendor}=="19d2", ATTRS{idProduct}=="0031", RUN+="/usr/local/bin/ppp-gsm-custom.sh zte-mf180 remove"

# Детектирование подключения "Nokia 3110c"
SUBSYSTEMS=="usb", KERNEL=="ttyACM*", ACTION=="add", ATTRS{modalias}=="usb:v0421p005E*", ATTRS{bInterfaceNumber}=="01", ATTRS{bInterfaceProtocol}=="01", RUN+="/usr/local/bin/ppp-gsm-custom.sh nokia-3110c add $kernel"

# Детектирование отключения "Nokia 3110c"
SUBSYSTEMS=="usb", ACTION=="remove", ATTRS{idVendor}=="0421", ATTRS{idProduct}=="005e", RUN+="/usr/local/bin/ppp-gsm-custom.sh nokia-3110c remove"

После сохранения файла даём указание подсистеме UDEV перечитать и принять новую конфигурацию:

# udevadm control --reload-rules

Теперь напишем скрипт, который будет отрабатывать событие и осуществлять управление подключением:

# touch /usr/local/bin/ppp-gsm-custom.sh
# chmod ugo+x /usr/local/bin/ppp-gsm-custom.sh

#!/bin/bash

# Получаем имя профиля оборудования (специфика модема и провайдера)
PEER="${1}"
# Получаем статус события (add или remove)
ACTION="${2}"
# Получаем имя интерфейса, к которому подключен модем
ADDR="/dev/${3}"

# Указываем скорость передачи данных интерфейса
SPEED="460800"
# Указываем приложение (или скрипт), которое подготовит соединение между аппаратурой клиента и сервера удалённого доступа до того уровня, на котором уже возможен запуск передачи данных по протоколу PPP
CONNECT="/usr/sbin/chat -v -f /etc/ppp/peers/${PEER}.chat"
# Указываем конфигурационный файл, описывающий условия работы с целевым оборудованием
CONFIG="/etc/ppp/peers/${PEER}.conf"
# Указываем путь для файла журнала событий
LOG="/var/log/ppp-gsm-${PEER}.log"

# На всякий случай создаём файл журнала, если таковой отсутствует
[ ! -f "${LOG}" ] && touch "${LOG}"

# Выясняем PID целевого PPP-сеанса, если таковой уже запущен
PID=`ps wax | grep --invert-match grep | grep --max-count=1 --ignore-case "pppd[ ]*${ADDR}" | awk '{print $1}'`

case "${ACTION}" in
  add)
    # Проверяем существование "символьного" файла модема
    [ ! -c "${ADDR}" ] && exit 1

    if [ "${PID}" == "" ]; then
      /usr/sbin/pppd ${ADDR} ${SPEED} connect "${CONNECT}" file ${CONFIG} logfile ${LOG} &
    fi
  ;;
  remove)
    if [ "${PID}" != "" ]; then
      kill -s KILL ${PID}
    fi
  ;;
  *)
    exit 1
  ;;
esac

exit 0

Подготовим профили подключений.

Просто для того, чтобы обезопаситься от использования нецелевого имени и пароля (в случае ошибки или опечатки), заводим в "chap-secrets" и "pap-secrets" пользователя, от имени которого будем проходить фиктивную процедуру аутентификации, если такая будет запрошена сервером (и запрашивается, что забавно, при том, что для оператора сотовой связи она бессмыслена):

# echo "internet  *  internet" >> /etc/ppp/chap-secrets
# echo "internet  *  internet" >> /etc/ppp/pap-secrets

Создаём конфигурационный файл параметров PPP-сессии, именуя его в соответствии с выбранной ранее политикой. Например, в нашем случае для модема "ZTE MF180" UDEV будет передавать скрипту строку "zte-mf180":

# touch /etc/ppp/peers/zte-mf180.conf

# Если не указать явно имя пользователя, то клиент PPP шлёт в качестве такового имя компьютера
user internet

# Явно задаём режим работы, в котором мы не требуем аутентификации у сервера удалённого доступа (большинство публичных провайдеров её и не предоставят)
noauth

# Включаем поддержку аппаратного контроля целостности потока передаваемых данных (hardware flow control), разгружая тем самым процессор компьютера
crtscts

# Если на стороне клиента или сервера удалённого доступа установлено не особо интеллектуальное оборудование, то, возможно, придётся отключить сжатие данных с помощью того или иного набора алгоритмов (определить точку сбоя поможет временно включенный режим "отладки")
# noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp

# Задаём период (в секундах) обмена служебными (предназначенными для настройки параметров взаимодействия канала передачи данных между клиентом и сервером удалённого доступа) LCP-пакетами (для детектирования "зависшей" линии передачи данных)
lcp-echo-interval 10
# Объявляем соединение "зависшим" после нескольких неудачных попыток обмена LCP-пакетами
lcp-echo-failure 3

# Указываем клиенту PPP инициировать соединение с сервером удалённого доступа в случае обнаружения разрыва такового
persist

# Задаём максимальное количество попыток соединения, после которых клиент PPP должен прекратить работу (0 - неограниченное количество)
maxfail 0

# Задаём паузу (в секундах) между попытками осуществить соединение с сервером удалённого доступа
holdoff 5

# Пресекаем использование уже имеющихся IP-адресов сетевых интерфейсов компьютера в качестве "локального" для соединения PPP, настаивая на автоматическом получение сетевых настроек от сервера удалённого доступа
noipdefault

# Запрашиваем у сервера удалённого доступа список DNS-серверов (я отключаю эту опцию, так как имею собственные DNS-сервера, указанные в "/etc/resolv.conf")
# usepeerdns

# Указываем сделать шлюз, полученный от сервера удалённого доступа, маршрутом "по умолчанию" для системы в целом (вторая опция уточняет поведение клиента PPP, на тот случай, если в системе уже имеется маршрут "по умолчанию" - он будет перезаписан новым)
defaultroute
replacedefaultroute

# Детализируем вывод сообщений о статусе соединения (полезно только тогда, когда локализуется проблема)
# debug

# Указываем не переводить приложение в "фоновый" режим, оставляя прикреплённым его к той консоли, в которой оно было запущено (полезно для быстрой оценки текущего статуса соединения во время локализации проблемы)
# nodetach

Конфигурационный файл сессии PPP для подключения к "интернету от Bee-Line" через модем "Nokia 3110c" аналогичен тому, что мы написали для "интернета от K-Cell" через модем "ZTE MF180". Просто копируем файл в новый, с соответствующим именем:

# cp /etc/ppp/peers/zte-mf180.conf /etc/ppp/peers/nokia-3110c.conf

Создаём файл со строками инициализации, который будет использоваться скриптом подготавливающим соединение между аппаратурой клиента и сервера удалённого доступа до того уровня, на котором уже возможен запуск передачи данных по протоколу PPP. Этот файл - для соединения с "K-Cell" через модем "ZTE MF180":

# touch /etc/ppp/peers/zte-mf180.chat

'ECHO'     'ON'
'TIMEOUT'  '10'
'ABORT'    'BUSY'
'ABORT'    'ERROR'
'ABORT'    'NO ANSWER'
''         'ATZ'
''         'AT+ZSNT=0,0,2'
'OK'       'AT+CGDCONT=1,"IP","internet"'
'OK'       'ATDT*99#'
'TIMEOUT'  '30'
CONNECT

Строка инициализации у "Bee-Line" через "Nokia 3110c" несколько иная, потому конфигурацию для инициализации канала создаём отдельно:

# touch /etc/ppp/peers/nokia-3110c.chat

'ECHO'     'ON'
'TIMEOUT'  '10'
'ABORT'    'BUSY'
'ABORT'    'ERROR'
'ABORT'    'NO ANSWER'
''         'ATZ'
'OK'       'AT+CGDCONT=1,"IP","internet.beeline.kz"'
'OK'       'ATDT*99#'
'TIMEOUT'  '30'
CONNECT

На этом подготовительные работы заканчиваются. Подключаем модем и проверяем содержимое журнала событий:

# cat /var/log/ppp-gsm-zte-mf180.log

ATZ
OK
AT+ZSNT=0,0,2
OK
AT+CGDCONT=1,"IP","internet"
OK
ATDT*99#
CONNECT
Serial connection established.
Using interface ppp0
Connect: ppp0 <--> /dev/ttyUSB2
CHAP authentication succeeded
Could not determine remote IP address: defaulting to 10.64.64.65
local  IP address 10.93.198.69
remote IP address 10.64.64.65
primary   DNS address 2.78.43.17
secondary DNS address 2.78.43.18

Отлично, мы уже "в интернете".

Если мы вынем модем из "USB-порта", отработают правила UDEV, которые запустят скрипт завершения сессии PPP. Работа программы будет корректно завершена, о чём в журнале событий появится соответствующая запись:

# cat /var/log/ppp-gsm-zte-mf180.log

Modem hangup
Connect time 3.0 minutes.
Sent 0 bytes, received 28 bytes.
Connection terminated.

Вот как-то так обеспечивается у меня подключение к сети интернет на "нетбуке". Учитывая то, что при первой-же возможности я заменил в нём встроенный HDD на SSD, проверить почту и вообще, поработать, я могу где угодно: в движении на машине, в поезде, в кафе, в парке - да вообще, везде, в зоне покрытия провайдера мобильной связи.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )