n_gsm Линейная дисциплина с модемом Telit LE910B1 и CMUX - PullRequest
1 голос
/ 15 января 2020

Мы используем модем Telit LE910B1 на встроенном устройстве с ядром Linux 5.1.0. У нас есть только один UART, доступный для модема, поэтому мы используем линейную дисциплину n_gsm с CMUX на модеме. Когда все настроено, наше приложение создает два виртуальных ttys, использует одно для получения информации о модеме, а другое передается pppd для запуска сеанса PPP. Затем мы можем запустить данные RX / TX через TCP / IP. Все это работает хорошо в течение короткого времени, с небольшими передачами данных, но когда мы пытаемся передать большие объемы данных, соединение PPP блокируется, и единственный способ возобновить работу - это отключить pppd, выключить и включить модем и перезапустите приложение.

Telit смогла воспроизвести проблему с двумя разными версиями Ubuntu (18.04 и) и смогла получить информацию о трассировке от модема, которую они передали Intel для дальнейшей диагностики. Ответ Intel был что они думают, что «сторона приложения хоста», возможно, не делает правильные кадры CMUX или не учитывает максимальный размер кадра. Вот некоторые выдержки, предоставленные нам Telit из анализа трассировки модема:

<-- Packet discarded because of flag("0xF9") missing in CMUX frame.
<-- Packet discarded because of dlc is not valid in frame.
<-- Packet discarded because of length size more then RD_BUF_SIZE = 1510
<-- Packet dropped because of in PPP frame FCS is not valid

В моем случае «сторона приложения хоста» - это драйвер n_gsm в Linux, и я могу установить только размеры mru и mtu, которые я установил в то, что Telit говорит по умолчанию для модема (т.е. 121).

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

struct termios tio;
int serial_fd;

serial_fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(serial_fd, &tio);
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL;
tio.c_cflag |= CRTSCTS;
tio.c_lflag = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;

cfsetospeed(&tio, B115200);
cfsetispeed(&tio, B115200);
tcsetattr(serial_fd, TCSANOW, &tio);

Для настройки модема я использую следующее:

send_at_command(serial_fd, "ATE0V1&K3&D2\r");
send_at_command(serial_fd, "AT#CMUXMODE=5\r");
send_at_command(serial_fd, "AT+CMUX=0,0\r");

После этого я включаю дисциплину n_gsm

struct gsm_config gsm;

int ldisc = N_GSM0710;
ioctl(serial_fd, TIOCSETD, &ldisc);
ioctl(serial_fd, GSMIOC_GETCONF, &gsm) ;

gsm.initiator = 1;
gsm.encapsulation = 0;
gsm.mru = 121;
gsm.mtu = 121;

ioctl(serial_fd, GSMIOC_SETCONF, &gsm);
/* Create /dev/ttyGSM1 and /dev/ttyGSM2. Do not close /dev/ttyS1 */

кто-нибудь еще использовал модем LE910 * с линейной дисциплиной CMUX и n_gsm в ядре Linux 5.1.0 или новее? Были ли у вас проблемы? Есть ли проблемы с кодом, который я показал, или вы можете предложить что-то, что я мог бы попробовать?

РЕДАКТИРОВАТЬ

Я посмотрел на код драйвера n_gsm. c и обнаружил, что есть 3 уровня трассировки, которые вы можете включить. Я начал с включения уровней 4 и 2:

echo "6" > /sys/module/n_gsm/parameters/debug

, и это будет регистрировать пакеты по мере их сборки и отправки в tty. Я обнаружил, что Intel правильно сказала. Драйвер отправляет мусор на модем. Журнал показывает, что нормальные пакеты выходят, но затем это:

Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000000: f9 0b ef f3 21 45 10 05 74 aa 6a 40 00 40 06 d1  ....!E..t.j@.@..
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000010: a5 46 19 8e 6f cc 65 18 76 00 16 0b 58 5b e6 da  .F..o.e.v...X[..
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000020: 55 bd 3e 38 ad 80 18 1f 4a 4d dc 00 00 01 01 08  U.>8....JM......
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000030: 0a 65 3c e5 73 7b 9d 4c 86 f8 53 e4 9f ff a4 9e  .e<.s{.L..S.....
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsmld_output: 00000060: 27 3c ee ab 28 29 51 e7 4e 04 f4 70 ce d4 e3 f2  '<..()Q.N..p....
Jan 19 18:09:51 ZFG0000805 kern.debug kernel: gsmld_output: 00000070: 93 ed 71 30 c7 1e 93 d8 b3 4a 90 88 e7 f9        ..q0.....J....

Обычно вы видите пинок, сопровождаемый выводом, где пакет точно такой же, но не здесь. Пакеты CMUX должны начинаться и заканчиваться байтом 0xf9, но «выходной» пакет выглядит поврежденным. После этого все записи в пике показывают завершенные пакеты, но следующая трассировка вывода начинается на один байт от символа начала кадра.

Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000000: f9 0b ef f3 87 8d e0 d0 db 2a 22 96 92 80 b6 a4  .........*".....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000010: 31 33 43 f0 13 e9 f3 79 13 d9 b4 13 8a 85 10 15  13C....y........
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000020: 26 0d ab c2 89 f2 ad a2 6f cd 5d a9 15 f2 fe e8  &.......o.].....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000030: 6a 90 06 ef f3 d2 4c c1 65 4e 3c 22 f5 db f8 66  j.....L.eN<"...f
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000040: d5 d7 70 fa f5 47 03 09 52 d3 1f 30 91 55 20 ce  ..p..G..R..0.U .
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000050: bc 71 51 b5 f7 ac f4 2a 7d 5d 1d 47 8d 30 73 22  .qQ....*}].G.0s"
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000060: 38 fa 39 f4 64 9f f6 7d 5d 7d 5d 2a ab b6 a6 cf  8.9.d..}]}]*....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsm_data_kick: 00000070: 76 dd 8f 0a fd 27 8f 09 b2 78 99 da f8 e7 f9     v....'...x.....
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000000: 0b ef f3 87 8d e0 d0 db 2a 22 96 92 80 b6 a4 31  ........*".....1
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000010: 33 43 f0 13 e9 f3 79 13 d9 b4 13 8a 85 10 15 26  3C....y........&
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000020: 0d ab c2 89 f2 ad a2 6f cd 5d a9 15 f2 fe e8 6a  .......o.].....j
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000030: 90 06 ef f3 d2 4c c1 65 4e 3c 22 f5 db f8 66 d5  .....L.eN<"...f.
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000040: d7 70 fa f5 47 03 09 52 d3 1f 30 91 55 20 ce bc  .p..G..R..0.U ..
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000050: 71 51 b5 f7 ac f4 2a 7d 5d 1d 47 8d 30 73 22 38  qQ....*}].G.0s"8
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000060: fa 39 f4 64 9f f6 7d 5d 7d 5d 2a ab b6 a6 cf 76  .9.d..}]}]*....v
Jan 19 18:09:52 ZFG0000805 kern.debug kernel: gsmld_output: 00000070: dd 8f 0a fd 27 8f 09 b2 78 99 da f8 e7 f9        ....'...x.....

Теперь действительно странная часть. Когда я включаю ведение журнала пакетов,

echo "7" > /sys/module/n_gsm/parameters/debug

Пакеты регистрируются непосредственно перед отправкой в ​​очередь для отправки. Это замедляет работу всей системы, но, что бы я ни пытался, я не мог заставить сетевую сессию зависать. Казалось, все работало нормально, хотя было ужасно медленно.

1 Ответ

0 голосов
/ 04 марта 2020

Подобная проблема у нас есть во встроенном Linux с ядром 4.1.15 и ubuntu с ядром 5.3.0.

Передача небольших порций данных работает очень хорошо, когда выполняется большая передача данных (iperf, scp, ...) в восходящем направлении (host -> world) ppp прекращает отправку данных на некоторый период времени (около 30 с).

Но мы не видим проблемы с искаженными пакетами (как в исходном вопросе) и проблема исчезла, если включена отладка.

Откуда возникает эта проблема. Когда DLCI fifo заполнен, функция gsmtty_write возвращает значение 0. После 3 попыток ppp отключается на некоторый период времени (по наблюдениям это примерно 30 секунд, но не уверен насчет точного времени / условий).

Что такое в коде отсутствует tty_wakeup при освобождении DLCI fifo или ниже определенного порога.

Мы работаем над тем, чтобы исправить это. С нижним патчем проблема исчезла, но она далека от финального патча.

--- a/n_gsm.c
+++ b/n_gsm.c
@@ -2408,6 +2408,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
 {
        struct gsm_mux *gsm = tty->disc_data;
        unsigned long flags;
+       struct tty_struct *tty_dlci = NULL;
+       int i = 0;

        /* Queue poll */
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -2416,7 +2418,33 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
        if (gsm->tx_bytes < TX_THRESH_LO) {
                gsm_dlci_data_sweep(gsm);
        }
+
+       while (i < NUM_DLCI) {
+               struct gsm_dlci *dlci;
+
+               if (debug & 200)
+                       printk("%s: gsm->tx_bytes: %u\n", __FUNCTION__, gsm->tx_bytes);
+
+               if (gsm->tx_bytes > TX_THRESH_HI)
+                       break;
+
+               dlci = gsm->dlci[i];
+               if (dlci == NULL) {
+                       i++;
+                       continue;
+               }
+               if (kfifo_len(dlci->fifo) < 2048)  {
+                       tty_dlci = tty_port_tty_get(&dlci->port);
+                       if (tty_dlci)
+                               printk("We should call tty_wakeup for DLCI %d, tty_dlci: 0x%x\n", i, (unsigned int) tty_dlci );
+               }
+               i++;
+       }
+
        spin_unlock_irqrestore(&gsm->tx_lock, flags);
+
+       if (tty_dlci)
+               tty_wakeup(tty_dlci);
 }

 /**
...