Гейтвей на колесах

В данной статье пойдет речь о применении автомобильных гейтвеев на примере Toyota RAV4 4-го поколения. Этот автомобиль выбран неспроста: гейтвей на нем появился в середине жизненного цикла, поэтому можно провести наглядное сравнение до/после в рамках одной модели. Также данный блок оказался сравнительно простым, без экзотических интерфейсов: CAN и только CAN.

Статья поможет ответить на следующие вопросы:

  1. Мешает ли гейтвей прослушивать трафик через разъем OBD2?

  2. Как внедрение гейтвея повлияло на процедуру диагностики?

  3. Как внедрение гейтвея повлияло на загрузку данных, например, обновление калибровок?

Что же такое автомобильный гейтвей?

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

image-loader.svg

Протоколы при этом могут быть самыми разными: CAN, LIN, FlexRay, Ethernet и т.д.

К основным возможностям гейтвея относят:

  • фильтрация трафика (изолирование сетей от уязвимых или избыточных данных, например изоляция диагностического разъема OBD2 от прикладных данных);

  • маршрутизация прикладных данных (обеспечение обмена «рабочими» данными между блоками автомобиля, например: обороты коленвала, состояние подушек безопасности и т.д.);

  • маршрутизация диагностических данных (обеспечение надежного соединения между диагностическим оборудованием и диагностируемым блоком);

  • трансляция протоколов (например, преобразование и передача данных из CAN в LIN и наоборот).

К расширенным возможностям можно отнести:

  • обнаружение вторжения (например, появление подозрительного трафика на CAN-шине двигателя с целью обхода иммобилайзера);

  • обновление блоков (например, с помощью OTA, с последующей перезагрузкой и проверкой состояния блока);

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

Гейтвеи становятся умнее с каждым новым поколением автомобилей и выполняют все больше функций, поэтому этот список постоянно растет.

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

Конкретный пример: Toyota

Чтобы перейти от общего к частному, изучим главного героя статьи поближе. Это деталь с партномером 89111–42020, компактная пластиковая коробочка с одним разъемом на 24 пина. Произведем вскрытие, чтобы увидеть, что у нее внутри:

556e481a13db719f3c442b487f33c1ab.jpg

На борту оказались микроконтроллер uPD70F4178 фирмы Renesas и high-speed CAN трансиверы TJA1049 фирмы NXP Semiconductors. Согласно информации из даташита, uPD70F4178 может использовать до 6 CAN шин. И действительно, на плате можно насчитать все 6 трансиверов, что многовато, т.к. RAV4 использует только 4 из них, но позже мы поймем, почему их столько.

Пинов у блока не так много, поэтому на основе электросхем можно быстро восстановить распиновку гейтвея:

Пины CAN с буквенным индексом — терминирующие, там просто резисторы.

Пользуясь распиновкой и остатками проводки, запитываем гейтвей на столе и пробуем поговорить с ним по диагностическому протоколу. Чтобы это сделать, нужно знать два адреса: по какому отправлять запрос и по какому получать ответ. На это ушло некоторое время, т.к. ни один адрес из распространенного диагностического диапазона 0×700 — 0×7FF не подходил, блок продолжал упорно молчать. Все остальные возможные 11-битные адреса тоже не давали результатов. Ну раз это гейтвей, то может быть он использует расширенные 29-битные адреса для диагностики? Можно попробовать перебрать, но и адресов там гораздо больше.

Чтобы не тратить время на перебор, провернем следующий трюк — притворимся автомобилем и пообщаемся через CAN шину с диагностическим ПО Techstream. После нескольких попыток узнаем, что правильный адрес запроса — это 0×750 и 0×5F в нулевом байте, то есть обмен выглядит так:

ID: 750    DLC:  8    5f XX XX XX XX XX XX XX
ID: 758    DLC:  8    5f XX XX XX XX XX XX XX

где 0×758 — это адрес ответа. Один байт полезных данных всегда занят значением 0×5f, снижая полезную нагрузку кадра.

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

Они работают следующим образом: в пределах выбранного диапазона адресов рассылаются UDS запросы DiagnosticSessionControl (0×10) с переключением в defaultSession (0×01), т.к. это самый базовый и относительно безобидный запрос, и ожидается ответ. Далее предполагаются три варианта развития событий: 1) блок откликнется подтверждением операции (0×50), 2) блок откликнется отказом (0×7f), 3) блок не откликнется совсем. В случаях 1 и 2 адрес отклика может потенциально скрывать за собой искомый блок, ну, а в случае 3 адрес инкрементируется и поиски продолжаются.

Наконец-то заполучив адреса, переберем все возможные значения сессий для запроса DiagnosticSessionControl (0×10) и посмотрим на отфильтрованный результат:

ID: 750    DLC:  8    5f 02 10 01 00 00 00 00
ID: 758    DLC:  8    5f 01 50 00 00 00 00 00

ID: 750    DLC:  8    5f 02 10 02 00 00 00 00
ID: 758    DLC:  8    5f 03 7f 10 22 00 00 00

ID: 750    DLC:  8    5f 02 10 5f 00 00 00 00
ID: 758    DLC:  8    5f 02 50 01 00 00 00 00

ID: 750    DLC:  8    5f 02 10 60 00 00 00 00
ID: 758    DLC:  8    5f 03 7f 10 22 00 00 00

ID: 750    DLC:  8    5f 02 10 70 00 00 00 00
ID: 758    DLC:  8    5f 03 7f 10 22 00 00 00

где 0×01 — defaultSession, 0×02 — programmingSession; 0×5f попадает в диапазон vehicleManufacturerSpecific, а 0×60 и 0×70 — в диапазон systemSupplierSpecific.

Проделаем тоже самое для сервиса SecurityAccess (0×27):

ID: 750    DLC:  8    5f 02 27 3b 00 00 00 00
ID: 758    DLC:  8    5f 10 12 67 3b XX XX XX
...
ID: 750    DLC:  8    5f 02 27 4f 00 00 00 00
ID: 758    DLC:  8    5f 10 12 67 4f XX XX XX
...
ID: 750    DLC:  8    5f 02 27 51 00 00 00 00
ID: 758    DLC:  8    5f 10 12 67 51 XX XX XX

Обнаружены 3 действующих варианта запроса, каждый из который возвращает seed длиной в 16 байт. Посылка рандомных ключей разной длины дает понять, что длина ключа тоже 16 байт.

Что скрывается за этими сессиями и уровнями доступа — пока неинтересно, но мы ими еще займемся.

Занимательная картография

А как выглядит гейтвей в естественной среде обитания, в автомобиле?
Настоящего, физического RAV4 у нас нет, поэтому окунемся с головой в электросхемы Toyota. Как упоминалось в начале статьи, RAV4 4-го поколения пережил внедрение гейтвея приблизительно в середине своего существования. Этот переход хорошо видно, если сравнить электросхемы для автомобилей выпущенных до и после октября 2015 года.

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

Начнем с анализа исходной системы (до октября 2015 года):

image-loader.svg

На схеме видно, что большинство блоков автомобиля подключены к одной шине, которая ведет к диагностическому разъему DLC3 (Data Link Connector), он же OBD2. Есть несколько изолированных участков сети, например, соединение между блоком управления двигателем (ECM) и трансмиссией. За блоком Main Body ECU спрятана еще одна небольшая сеть, отвечающая за комфорт и камеру заднего вида. Правый блок контроля слепых зон (Blind Spot Monitor Sensor RH) изолирован от основной шины и общается с ней через левый блок контроля слепых зон (Blind Spot Monitor Sensor LH).

Переходим к следующей схеме, уже с гейтвеем (после октября 2015 года):

image-loader.svg

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

  • диагностический (черного цвета), к которому подключается диагностическое оборудование через разъем OBD2;

  • основной (синего цвета), внутри которого находятся критически важные блоки управления двигателем, трансмиссией и кузовной электроникой;

  • ассистентов (желтого цвета), объединяет сенсоры, радары и камеры, которые помогают водителю;

  • инфотейнмента (красного цвета), содержит в себе навигацию, головное устройство, и модуль телематики.

Поменялась не только общая структура сети, но и количество ее узлов. Был добавлен блок телематики и целая группа блоков помощи водителю, которые устанавливались только при наличии гейтвея, и у этого есть веские причины.

Телематику и головное устройство обычно изолируют, так как они подвержены удаленной атаке, которая потенциально может привести к контролю над некоторыми функциями автомобиля. Пример, ставший уже классическим — взлом Jeep Cherokee в 2015 году.

А вот системе ADAS (Advanced Driver Assistance System) отводят отдельный домен, поскольку ее основные узлы — это камеры и разнообразные датчики, генерирующие большой поток данных, который нужно обрабатывать в реальном времени. Большинству модулей автомобиля этот трафик не нужен и только нагружает сеть, поэтому его можно без проблем вынести «за скобки».

В принципе, на этом можно было бы переходить к следующему этапу, но не помешает вспомнить о двух «лишних» трансиверах, которые были обнаружены в прошлом параграфе. Как оказалось, блок с такой же начинкой можно найти и в других автомобилях производителя.

Например, в Lexus RX 4-го поколения, где модуль гейтвея заведует уже всеми 6-ью шинами. Разнообразной электроники там тоже побольше — люкс, все-таки:

image-loader.svg

Сегменты сети, по порядку:

  • диагностический (красного цвета);

  • двигателя (зеленого цвета);

  • инфотейнмента (голубого цвета);

  • рулевого управления, ходовой части и тормозов (синего цвета);

  • комфорта и кузовной электроники (черного цвета);

  • ассистентов (бежевого цвета).

При этом за кадром осталась подсеть головного устройства «AVC-LAN», которая имеет отдельную схему в документации Lexus.

Обычно автопроизводители считают каждый цент и выгрызают все опциональные компоненты, но конкретно в этом случае Toyota не экономила и запаивала их даже там, где они не используются. Скорее всего в целях унификации или упрощения технологии производства.

Таблицы фильтрации: дубль первый

Результаты первых экспериментов показали, что модуль относительно несложный и просто выполняет фильтрацию на основе адреса принятого сообщения.

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

Всего имеется 4 домена, которые образуют 12 возможных пар:

Примечание: далее ради компактности обозначения доменов будут применяться сокращения: DIAG — диагностический, MAIN — основной, ASSI — ассистентов, INFO — инфотейнмента.

Для каждой пары нужно перебрать все 2048 (0×800) возможных адресов, это число обусловлено размером 11-битного CAN ID. Для каждого сочетания подключаем два CAN-интерфейса, один из которых будет передавать сообщения, а второй — принимать. Адреса «просеянных» сообщений вынесем в результирующую таблицу.

Первая таблица справедлива для всех сочетаний, в которых есть домен DIAG, то есть для всех случаев, когда к автомобилю подключено диагностическое оборудование через разъем OBD2: ASSI->DIAG, MAIN->DIAG, INFO->DIAG, DIAG->ASSI, DIAG->MAIN, DIAG->INFO.

image-loader.svg

Пропускаются только определенные сообщения с адресами из диагностического диапазона (0×700 — 0×7FF). Таблица содержит адреса и запросов и ответов, то есть может работать в обе стороны, и одинакова для всех доменов. Гейтвей не мешает диагностическим сообщениям, он для них прозрачен.

Остальные таблицы спрятаны под спойлер, чтобы не перегружать статью.

Дальнейшие таблицы регулируют обмен только собственных модулей автомобиля, без какого либо оборудования, подключенного к разъему OBD2.

Но что интересно, они все равно содержат диагностический диапазон, причем без пробелов. Любой модуль может отправлять в любой домен диагностическое сообщение и беспрепятственно получить ответ.

Выглядит это не очень безопасно. Давайте представим, что хакер смог заполучить контроль над модулем телематики из домена INFO. Поскольку правила фильтрации никак не ограничивают рассылку диагностических запросов из этого домена во все остальные, у потенциального злоумышленника открываются широкие просторы для творчества. Например, он может начать рассылать команды hard reset по всем адресам, погружая электронику автомобиля в хаос.

Таблица для пары MAIN->ASSI:

image-loader.svg

Таблица для пары INFO->ASSI:

image-loader.svg

Таблица для пары ASSI->MAIN:

image-loader.svg

Таблица для пары INFO->MAIN:

image-loader.svg

Таблица для пары ASSI->INFO:

image-loader.svg

Таблица для пары MAIN->INFO:

image-loader.svg

Пока все выглядит очень гладко, если бы не один момент: отсутствие адресов 0×001 и 0×002 при работе с диагностической шиной (самая первая таблица параграфа).
Дело в том, что для заливки калибровочных данных Toyota использует свой очень специфичный протокол, подробно описанный в популярной работе Adventures in Automotive Networks and Control Units.

Краткая выдержка протокола из этой работы

# ask PIDs supported
0000323409    <7E0>    [8]    02 09 00 00 00 00 00 00
0000323457    <7E8>    [8]    06 49 00 15 40 00 00 00
# ask calibration ID (< 16 ASCII chars)
0000323617    <7E0>    [8]    02 09 04 00 00 00 00 00
0000323649    <7E8>    [8]    10 23 49 04 02 33 34 37
0000323656    <7E0>    [8]    30 00 00 00 00 00 00 00
0000323665    <7E8>    [8]    21 31 35 32 30 30 00 00
0000323683    <7E8>    [8]    22 00 00 00 00 00 00 41
0000323697    <7E8>    [8]    23 34 37 30 31 30 30 30
0000323717    <7E8>    [8]    24 00 00 00 00 00 00 00
0000323733    <7E8>    [8]    25 00 00 00 00 00 00 00
0000334785    <7E8>    [8]    06 49 00 15 40 00 00 00
# ask seed
0000934292    <7E0>    [8]    02 27 01 00 00 00 00 00
0000934326    <7E8>    [8]    06 67 01 01 BB 8E 55 00
# send key
0000935970    <7E0>    [8]    06 27 02 01 DB EE 55 00
0000935991    <7E8>    [8]    02 67 02 00 00 00 00 00
# some sort of warning for other ECUs
0000937634    <720>    [8]    02 A0 27 00 00 00 00 00
0000939275    <720>    [8]    02 A0 27 00 00 00 00 00
0000940915    <720>    [8]    02 A0 27 00 00 00 00 00
# switch to reprogramming session
0000942564    <7E0>    [8]    02 10 02 00 00 00 00 00
0000942663    <7E8>    [8]    01 50 00 00 00 00 00 00
# Toyota's proprietary protocol
0000950636    <001>    [8]    01 00 00 00 00 00 00 00
0000950641    <001>    [8]    01 00 00 00 00 00 00 00
0000950648    <001>    [8]    06 20 07 01 00 02 00 00
0000950655    <001>    [8]    02 07 00 00 00 00 00 00
0000950663    <001>    [8]    04 EF 6F 1F BC 00 00 00
0000950676    <002>    [8]    01 3C 00 00 00 00 00 00
0000950680    <002>    [8]    10 10 38 39 36 36 33 2D
...

Адреса 0×001 и 0×002 должны быть указаны в правилах фильтрации, иначе было бы невозможно калибровать автомобили через диагностический разъем, например, во время отзывных кампаний.
Но где же они в таблицах?

Погружение в CUW

Чтобы разобраться с этим вопросом, вернемся к обнаруженным ранее сессиям и уровням доступа, вполне вероятно, что среди них кроется ответ. Сами по себе номера этих сервисов ничего не говорят, поэтому пришло время расковырять утилиту для калибровки CUW в поисках подробной информации.

CUW (Calibration Update Wizard) — это отдельная программа, входящая в состав диагностического комплекса Techstream от Toyota. Ее основная задача — это загрузка калибровочных данных в блоки автомобиля через диагностический интерфейс Toyota или другой J2534-совместимый интерфейс. Размер исполняемого файла программы всего несколько мегабайт и беглый просмотр показывает наличие большого количества текстовых символов и отладочных строк.

Открываем дизассемблер Ghidra и скармливаем ей CUW.

После пристального поиска находим некую сущность CCentralGWModeChanger в состав которой входят функции CollateSeedKey() и ChangeMode(), которые вызывают особый интерес. Давайте посмотрим, что у них внутри:

image-loader.svg

Хорошо видно, как буфер подготавливается к отправке, сначала в него загружаются идентификаторы сервиса — 0×27 для запроса seed и 0×10 для смены сессии, а далее мы видим уже знакомые байты 0×02/0×60 и 0×4f/0×51 соответственно. Выбор между этими байтами происходит по определенному условию.

Дальнейший поиск привел к двум функциям-оберткам ChangeToReprogMode() и ChangeToReprogGWMode(), которые и контролируют это условие, передавая флаг в качестве аргумента в CollateSeedKey() и ChangeMode():

Function

Flag

Seed/Key

Session

ChangeToReprogMode()

0

4f/50

02

ChangeToReprogGWMode()

1

51/52

60

Напрашивается вывод, что есть две различные ветки программы, одна вызывается для работы с гейтвеем, а другая — для всех остальных модулей.

Осталось дело за малым — найти алгоритм расчета ключа, чтобы получить доступ к нужным сессиям. Для этого ныряем вглубь CollateSeedKey() и находим функцию CalcSeedKey(), которая по уже знакомому флагу выбирает текстовый пароль длиной в 64 байта и скармливает его некой криптобиблиотеке CAES.

Из всех функций CAES наиболее активно используются PrepareKeyContainer(), ImportKey(), SetEncryptionMode() и Encrypt(), которые построены на API, очень уж похожем на wincrypt. Именно эта схожесть при дальнейшем анализе позволяет понять, что в качестве алгоритма задействован AES в простом режиме ECB.

Подытожим накопленную информацию в виде схемы:

image-loader.svg

Текстовый пароль с помощью некоторого алгоритма преобразуется в 16-ти байтную последовательность, которой шифруется запрошенный у модуля seed. Результатом этой операции является ключ, который необходимо отправить модулю для успешного получения доступа.

Все основные шаги ясны, сами пароли можно найти в незашифрованном виде прямо в exe-файле. Неизвестным остался только алгоритм преобразования. Признаться, здесь злую шутку с автором сыграла обычная лень. Вместо того, чтобы продолжить ковырять байты в Ghidra, было решено на авось искать алгоритм хеширования, который подойдет. Ведь пароли обычно хешируются, не так ли?

Когда MD5 остался далеко позади и в ход пошли крайне экзотические виды SHA под солями стало ясно, что что-то здесь не так, и нужно возвращаться к реверс-инжинирингу CUW. Благо большая часть работы уже была проделана, довольно быстро был обнаружен подозрительный кусок кода. После анализа процесс преобразования упрощенно можно представить в таком виде:

image-loader.svg

Каждый отдельный байт текстового 64-ех байтного пароля сдвигается вправо на 2 бита, затем из него вычитается 8. В результате получаются нибблы, из которых вновь склеивается текстовая строка, но уже размером в 32 байта. Теперь нужно взять числовые значения ASCII для каждых 2-ух байт этой строки и получить из них 1 итоговый байт.

Например, 4 байта пароля 0x30, 0x24, 0x2c, 0x30 дадут 2 промежуточных байта 0x41, 0x34, которые дадут 1 итоговый байт 0xA4.

Таблицы фильтрации: дубль второй

Теперь, когда секрет переключения в другую сессию раскрыт, запасаемся терпением и заново добываем таблицы уже знакомым способом. Не забываем корректно получить доступ и произвести само переключение.

И результат действительно есть — появились заветные ID 0×001 для запросов и 0×002 для ответов. Вдобавок к ним появились ID 0×003, 0×004, 0×005, 0×006, 0×008, 0×009.

Таблица для пар DIAG->MAIN, DIAG->ASSI, DIAG->INFO:

image-loader.svg

Таблица для пар ASSI->DIAG, MAIN->DIAG:

image-loader.svg

Таблица для пары INFO->DIAG:

image-loader.svg

Таблица для пар MAIN->ASSI, INFO->ASSI, ASSI->MAIN, INFO->MAIN, ASSI->INFO, MAIN->INFO:

image-loader.svg

Правила фильтрации гейтвея стали заметно жестче, теперь во всех направлениях пропускается только диагностический/калибровочный трафик, собственный трафик автомобиля полностью подавлен. Скорее всего, завести и полноценно эксплуатировать такую машину не получится.

Получается, что диагностическому ПО действительно нужно переключить гейтвей в другой режим и только потом производить калибровку. Остается один вопрос — как ПО понимает, что в автомобиле есть гейтвей? Для диагностических запросов он прозрачен, по году выпуска тоже однозначно не поймешь.

Теоретически, ПО может обратиться к гейтвею с обычным UDS-запросом, и если произойдет таймаут, то в автомобиле гейтвея нет и можно напрямую начинать калибровку выбранного модуля.

Чтобы проверить эту теорию, можно снова поставить эксперимент, притворяясь автомобилем и отвечая вместо него на запросы ПО. Открываем CUW и пробуем откалибровать любой относительно свежий автомобиль, в котором уже может стоять гейтвей. Сначала ПО производит стандартный опрос, используя PIDы OBD2:

# supported PIDs
ID: 07e0    DLC:  8    02 09 00 00 00 00 00 00
ID: 07e8    DLC:  8    06 49 00 ff ff 00 00 00
# calibration ID 
ID: 07e0    DLC:  8    02 09 04 00 00 00 00 00
ID: 07e8    DLC:  8    10 23 49 04 02 XX XX XX
ID: 07e0    DLC:  8    30 00 00 00 00 00 00 00
ID: 07e8    DLC:  8    21 XX XX XX XX XX 00 00
ID: 07e8    DLC:  8    22 00 00 00 00 00 00 XX
ID: 07e8    DLC:  8    23 XX XX XX XX XX XX XX
ID: 07e8    DLC:  8    24 00 00 00 00 00 00 00
ID: 07e8    DLC:  8    25 00 00 00 00 00 00 00
# supported PIDs
ID: 07df    DLC:  8    02 09 00 00 00 00 00 00
ID: 07e8    DLC:  8    06 49 00 ff ff 00 00 00
# VIN
ID: 07df    DLC:  8    02 09 02 00 00 00 00 00
ID: 07e8    DLC:  8    10 14 49 02 01 XX XX XX
ID: 07e0    DLC:  8    30 00 00 00 00 00 00 00
ID: 07e8    DLC:  8    21 XX XX XX XX XX XX XX
ID: 07e8    DLC:  8    22 XX XX XX XX XX XX XX

где: 0×7e0 — запрос к блоку двигателя, 0×7e8 — ответ от блока двигателя, 0×7df — широковещательный запрос.

Поняв, что версия калибровки отличается в меньшую сторону от желаемой, ПО запрашивает seed у гейтвея, не получает ответа и запрашивает seed у блока двигателя:

# get seed from gateway (timed out)
ID: 0750    DLC:  8    5f 02 27 51 00 00 00 00
# get seed from ECU
ID: 07e0    DLC:  8    02 27 01 00 00 00 00 00
...

Вот и весь механизм обнаружения — если что-то молчит, значит его нет.

Выводы

Вернемся после проделанной работы к вопросам, которые были озвучены в начале статьи и ответим на них.

  1. Мешает ли гейтвей прослушивать трафик через разъем OBD2?
    Да, он действительно фильтрует сообщения в обе стороны, поэтому прослушать или подмешать что-то в собственный трафик автомобиля через OBD2-разъем больше не получится — нужно будет врезаться в шину после гейтвея.

  2. Как внедрение гейтвея повлияло на процедуру диагностики?
    Для диагностики он прозрачен и запросы/ответы будут происходить так, как будто его и нет вовсе. Сам гейтвей тоже диагностируется и отображается в ПО, как и любой другой блок.

  3. Как внедрение гейтвея повлияло на загрузку данных, например, обновление калибровок?
    Для загрузки данных в определенный блок, нужно предварительно настроить гейтвей, и только потом отправлять их. Чтобы упростить процесс, производитель сделал процедуру калибровки совместимой для автомобилей с гейтвеем и без него.

В целом гейтвей оправдал проявленный интерес и оказался довольно любопытным блоком, который начал применяться в автомобилях сравнительно недавно. Изначально это были простые фильтры трафика, которые теперь перерастают в сложные системы, повышающие стабильность и безопасность взаимодействия узлов бортовой электроники.

© Habrahabr.ru