Телефон при включении не знает ни частот, ни сот вокруг — он должен просканировать эфир, выбрать подходящую соту, прочитать её служебную информацию, зарегистрироваться в сети и потом удерживать соединение при движении. Ниже разобрана механика этих шагов по исходникам srsRAN_4G, Open5GS и Magma: что именно делает RRC, что уходит в NAS и S1AP, какие таймеры запускаются и что происходит при обрыве.
Поиск соты: одна частота за раз
Процедура поиска соты работает с одной частотой. На старте она переводит себя в состояние phy_cell_search и просит PHYфизический уровень, который управляет радиооборудованием и выполняет измерения запустить поиск соты на этой частоте. Если PHY не смог начать поиск, процедура завершается ошибкой.
Пока идёт поиск и последующий выбор соты, шаг процедуры в состояниях phy_cell_search и phy_cell_select ничего не делает, кроме возврата yield — то есть процедура отдаёт управление вызывающему коду и возобновляет работу, когда придёт событие от PHY. Состояния si_acquire и wait_measurement делегируют работу отдельным шагам: чтению служебной информации и ожиданию измерений.
Когда PHY сообщает о найденной соте, процедура добавляет её в базу измерений, делает её обслуживающей сотойсотой, с которой UE в данный момент поддерживает связь, переводит себя в состояние phy_cell_select и просит PHY выполнить выбор соты. После выбора шаг step_wait_measurement() ждёт, пока RSRPуровень мощности принимаемого опорного сигнала, по которому оценивают качество соты станет нормальным числом. Затем проверяется наличие SIB1первого блока системной информации, из которого UE узнаёт идентификатор сети (PLMN) и код зоны отслеживания (TAC). Если SIB1 уже есть — процедура завершается успехом. Если нет — запускается отдельная процедура чтения служебной информации, и процедура переходит в состояние si_acquire.
Шаг step_si_acquire() ждёт завершения этой процедуры. Если чтение завершилось ошибкой, сота помечается как не найденная, но процедура всё равно возвращает успех — то есть неудача чтения SIB1 не считается сбоем самой процедуры поиска. При успешном чтении тоже возвращается успех.
Перебора частот здесь нет: процедура работает с одной частотой. Перебор реализован в другой процедуре — plmn_search_proc::step(), которая повторно запускает поиск соты до тех пор, пока в результате не придёт признак NO_MORE_FREQS.
Поиск сети: PLMN search и PLMN select
Поиск доступных PLMNидентификатор сети оператора, который телефон читает из служебной информации соты — это интерфейс между NAS и RRC. RRC перебирает все известные частоты, синхронизируется и принимает SIB1 на каждой, чтобы извлечь PLMN.
Запуск процедуры поиска сводится к двум действиям: попытке запустить процедуру поиска PLMN и добавлению её в список процедур, которые RRC периодически опрашивает. Внутри процедура инициализирует поиск ячеек, а на каждом шаге запускает его. Когда ячейка найдена и на ней есть SIB1, PLMN и TAC сохраняются в накопительный список found_plmns; если места в списке больше нет, выводится ошибка. Когда в результате поиска приходит NO_MORE_FREQS, процедура завершается успехом.
По завершении процедура сообщает NAS результат: при успехе — список найденных PLMN с их количеством, при ошибке — пустой указатель и -1.
Выбор сети — отдельная операция: она принимает идентификатор PLMN, устанавливает признак plmn_is_selected = true и сохраняет выбранный идентификатор, записывая это в лог.
События cell_search_complete и cell_select_complete — это интерфейс между RRC и PHY, а не между RRC и NAS. Первое передаёт результат поиска и найденную соту в PHY-контроллер, второе — результат выбора соты. Напрямую в NAS они не возвращаются.
Выбор соты: когда повторный запуск PHY не нужен
Процедура выбора соты сначала проверяет, совпадает ли переданная ячейка с текущей обслуживающей. Если не совпадает — устанавливает новую обслуживающую соту, сбрасывает признак discard_serving и переходит в состояние выбора, запуская PHY-выбор.
Если же ячейка уже была выбрана ранее (это и отмечено комментарием «in case the cell had already been selected»), повторный запуск PHY-выбора не нужен. В этой ветке процедура либо сразу завершается успехом, если обслуживающая сота пригодна, либо переходит к чтению служебной информации, если оно требуется.
Чтение служебной информации переводит процедуру в состояние cell_config и запускает конфигурирование обслуживающей соты с нужным набором SIB, возвращая yield. Шаг step_cell_search крутит поиск соты, пока тот не завершится, после чего либо запускает чтение SIB, либо завершает процедуру. Шаг step_cell_config крутит конфигурирование, пока оно не завершится, после чего при пригодной обслуживающей соте завершает процедуру успешно, а иначе логирует ошибку и запускает выбор следующей соты. Состояния cell_selection и serv_cell_camp в шаге просто возвращают yield, ожидая события от PHY.
Критерии пригодности соты
Пригодность обслуживающей соты — это конъюнкция четырёх условий: PHY в синхронизации, сота находится в состоянии кампингарежим, в котором UE «стоит» на соте и слушает её служебную информацию, проходят критерии выбора соты по RSRP и есть обязательные SIB.
Критерий выбора соты требует, чтобы RSRP был нормальным числом, у соты уже был SIB3 и вычисленный Srxlev был больше нуля. Srxlev считается так:
Qrxlevmeas - (Qrxlevmin + Qrxlevminoffset) - Pcompensationгде Pcompensation в текущей реализации равен нулю.
Чтение SIB требуется, когда UE уже синхронизировано и кампит, но обязательных SIB ещё нет: либо отсутствует SIB3, либо RSRP проходит критерий выбора соты. В процедуре восстановления соединения проверяются только синхронизация PHY и критерий выбора соты по RSRP — без проверки SIB.
Измерения: как значения попадают в базу
Геттеры RSRP и RSRQ (для EUTRA и для NR) — это интерфейсные функции: по частоте и PCIидентификатор физической соты, по которому различают соты на одной частоте они находят дескриптор соседней соты в базе измерений и возвращают сохранённое в нём значение, а если соты нет — NAN.
Значения попадают в базу из очереди измерений PHY. Функция, вызываемая из PHY, только кладёт вектор измерений в очередь и сразу возвращается — обработка выполняется позже из потока RRC. Обработчик извлекает измерения из очереди в цикле и для каждого обновляет RSRP, RSRQ и CFO ячейки через фильтры. Для NR измерения кладутся в отдельную очередь, конвертируются и записываются в NR-базу тем же фильтром.
Если состояние — CONNECTED, были добавлены соседние ячейки и обработчик хэндовера не занят, вызывается обновление PHY, чтобы сообщить ему о новых ячейках для измерения.
Установка соединения: от запроса до ConnectionSetupComplete
Процедура запроса соединения инициируется с причиной установления и SDUблок данных, который NAS передаёт RRC для отправки в сеть dedicatedInfoNAS. На старте проверяется, что PLMN выбран, состояние — IDLE и таймер T302 не запущен. T302 — это таймер запрета повторной попытки установления соединения: пока он идёт, UE не имеет права запрашивать соединение заново. Если T302 запущен, включается запрет mo_data и процедура возвращает ошибку.
После выбора и конфигурирования обслуживающей соты запускается таймер T300 и отправляется ConnectionRequest в UL CCCHобщий восходящий канал, по которому UE шлёт запросы до установления соединения. T300 отсчитывает время ожидания ответа сети на запрос установления соединения: если ответ не пришёл до его истечения, попытка считается неудачной. В этом сообщении идентификатор UE формируется одним из двух способов: если идентификатор сконфигурирован, он берётся как S-TMSIвременный идентификатор абонента, выданный сетью; иначе — как 40 случайных бит. Причина установления берётся из переданного значения.
После отправки запроса SDU dedicatedInfoNAS сохраняется. Если там уже лежал старый SDU, он сбрасывается с предупреждением. Если SDU не был передан, выводится отладочное сообщение, что он уже предоставлен RRC.
Далее процедура ждёт в состоянии wait_t300. При переходе в состояние CONNECTED она возвращает успех. При истечении T300 сбрасывается MAC, применяется MAC-конфигурация по умолчанию и переустанавливается RLC. При остановке T300 без соединения (получен ConnectionReject) сбрасывается MAC и применяется MAC по умолчанию.
Процедура настройки соединения принимает выделенную радиоконфигурацию и SDU dedicatedInfoNAS. Она требует наличия SDU, применяет радиоконфигурацию, снимает запрет barring none и, если конфигурация PHY не ожидается, сразу переходит к завершающему шагу. На нём отправляется ConnectionSetupComplete в UL DCCHвыделенный восходящий канал для сигнальных сообщений после установления соединения: SDU копируется в поле ded_info_nas, устанавливается sel_plmn_id = 1 и идентификатор транзакции, а сообщение уходит по SRB1первом сигнальном радиоканале, по которому идёт управляющая информация RRC.
Регистрация на MME: InitialUEMessage и S-TMSI
Сообщение InitialUEMessage формируется так: если S-TMSI есть, заполняются его поля m_tmsi и mmec; затем добавляются идентификатор UE на стороне eNB, NAS-PDU, TAI, EUTRAN-CGI и причина установления RRC. PLMN в этом сообщении не передаётся — вместо него идут TAI и EUTRAN-CGI, взятые из состояния eNB.
На стороне MME обработчик извлекает из сообщения ENB_UE_S1AP_ID, NAS_PDU, TAI, EUTRAN_CGI и S_TMSI. Если ENB_UE_S1AP_ID отсутствует или его значение больше 0x00ffffff, отправляется Error Indication с semantic_error. Если контекст eNB-UE не найден, создаётся новый, и при наличии S-TMSI выполняется поиск MME-UE: PLMN берётся из первого сконфигурированного plmn_id, а mme_gid — из первого mme_gid.
При S1 Setup проверяется совпадение PLMN: если списки зон отслеживания не совпадают, генерируется S1 Setup Failure с причиной unknown_PLMN.
Связывание контекстов eNB-UE и MME-UE
MME сначала ищет существующий контекст eNB-UE по ENB_UE_S1AP_ID. Если не находит — создаёт новый и помечает его флагом «создан этим сообщением». Комментарий поясняет смысл: если последующая проверка обязательных информационных элементов не пройдёт, новый контекст нужно освободить до возврата, иначе некорректное InitialUEMessage может исчерпать пул eNB-UE. Уже существующий контекст (ветка else) не удаляется — чтобы легитимный активный контекст не был разрушен некорректным или дублирующим сообщением.
Связывание с MME-UE выполняется поиском по S-TMSI: если он присутствует, строится GUTIвременный глобально уникальный идентификатор абонента, собираемый из PLMN, группы MME и кода MME из первого сконфигурированного PLMN и mme_gid. В реализации Magma связь mme_ue_s1ap_id с ассоциацией и comp_s1ap_id хранится в картах mmeid2associd и ue_id_map.
Хэндовер: переключение на целевую соту
При получении RRCConnectionReconfiguration с MobilityControlInfo запускается процедура хэндовера. На старте сохраняются исходная сота и C-RNTI, останавливается T310таймер, который следит за потерей синхронизации с текущей сотой и запускается при обнаружении проблем с радиосвязью, запускается T304таймер, который отводит время на завершение хэндовера и запускается в момент переключения на целевую соту. Затем обслуживающая сота переключается на целевую, запускается выбор целевой соты, сбрасывается MAC, переустанавливаются RLC и PDCP, деактивируются SCell, и новый C-RNTI применяется через set_ho_rnti. Далее применяется общая радиоконфигурация, при наличии настраивается выделенный RACH, применяется выделенная радиоконфигурация, и перед сменой ключей сохраняются текущие ключи.
Обновление KeNBключ, из которого выводятся ключи шифрования и целостности для текущего соединения устроено так: если в конфигурации безопасности присутствует признак смены ключа, сначала генерируются ключи на основе свежего KASME, затем всегда генерируются ключи хэндовера с целевым PCI, целевой частотой и счётчиком цепочки, после чего новые ключи применяются в PDCP. При истечении T304 ключи восстанавливаются из исходной соты и снова применяются в PDCP. При успешном завершении Random Access T304 останавливается и применяются финальные конфигурации.
Хэндовер на стороне eNB и MME
На стороне eNB процедура подготовки хэндовера проверяет подключение к MME и наличие UE по RNTI, после чего запускается с целевыми ECI, TAC, PLMN, списком перенаправляемых E-RAB, контейнером RRC и признаком прямого пути. Список admitted E-RAB формируется не здесь, а в подтверждении: туда копируются admitted-носители, и для каждого при наличии адресов заполняются транспортные адреса нисходящего и восходящего направлений.
Контейнер Source-ToTarget формируется так: в него копируется RRC-контейнер, затем контейнер упаковывается и результат кладётся в поле source_to_target_transparent_container. На приёмной стороне обработчик распаковывает контейнер и передаёт его в RRC для выделения ресурсов.
На стороне MME обработчик HandoverRequired сначала находит описание исходного eNB по ассоциации; при неудаче обработка прекращается. Затем из контейнера извлекаются обязательные информационные элементы: MME UE S1AP ID, eNB UE S1AP ID, тип хэндовера, причина, TargetID и Source-ToTarget-TransparentContainer. Отсутствие любого возвращает ошибку. Тип хэндовера допускается только intralte. Целевой eNB выбирается из TargetID: только при targeteNB_ID, причём для homeENB_ID идентификатор вычисляется из 28-битного буфера, а для macroENB_ID — из 20-битного.
Обработчик HandoverRequest проверяет, что входной указатель не пуст, находит UE-контекст по mme_ue_s1ap_id, а описание целевого eNB — по target_sctp_assoc_id. Затем выбирается SCTP-стрим, сохраняются принимающий и отправляющий стримы, счётчик стримов инкрементируется с обёрткой на 1 при достижении числа входящих стримов, и карта eNB обновляется. Формируется сообщение HandoverRequest с обязательными элементами: MME UE S1AP ID, тип хэндовера, причина, агрегированная максимальная битовая скорость UE, список E-RAB для установки, Source-ToTarget-TransparentContainer, возможности безопасности UE и контекст безопасности. PDU кодируется и отправляется на целевой ассоциации.
Смена eNB без хэндовера
При Path Switch Request MME ищет существующий контекст UE по SourceMME_UE_S1AP_ID. Если не находит — отвечает Path Switch Failure с причиной unknown_mme_ue_s1ap_id. Затем проверяет, что исходный eNB ещё существует; иначе отправляет Path Switch Failure с причиной message_not_compatible_with_receiver_state.
Комментарий объясняет, зачем нужен исходный eNB: переключение контекста на новый eNB требует исходного, а MME удаляет контекст eNB-UE вместе с его eNB при потере S1-ассоциации. Поэтому проверка нужна, чтобы не разыменовывать удалённый eNB. В реализации OAI MME находит старый контекст по mme_ue_s1ap_id, проверяет уникальность нового ENB_UE_S1AP_ID и создаёт новый контекст на целевом eNB, удаляя старый с исходного.
Пейджинг: как сеть зовёт телефон
Сообщение Paging формируется как initiatingMessage с кодом процедуры Paging и критичностью ignore. UE Identity Index Value вычисляется как остаток от деления IMSI на 1024, приведённый к 16 битам:
UE_ID_INDEX_TO_BIT_STRING((uint16_t)(imsi64 % 1024), ...)Список TAC формируется в цикле по списку зон: для каждого элемента берётся количество TAC, и внутренний цикл выполняется на один раз больше указанного числа — то есть добавляется на один TAC больше. PLMN и TAC каждого элемента кодируются и добавляются в список. Затем PDU кодируется, и при ошибке или неположительной длине возвращается ошибка.
Сообщение отправляется только тем eNB, у которых есть ассоциация SCTP, состояние S1AP_READY и для которых сравнение списков зон отслеживания вернуло истину. Отправка идёт со stream id 0 и mme_ue_s1ap_id 0, потому что UE в IDLE.
Обработка пейджинга на телефоне
При получении PDU по PCCHканал пейджинга, по которому сеть вызывает UE в режиме ожидания RRC не разбирает его сразу, а кладёт в очередь команд с пометкой PCCH. Затем обработчик проверяет размер PDU (отбрасывает, если он неположительный или слишком большой), распаковывает сообщение и требует, чтобы его тип был c1. Если идентификатор UE не сконфигурирован, выводится предупреждение и обработка прекращается.
Список записей пейджинга обрезается до максимума, после чего запускается процедура обработки. Внутри неё сохраняется сообщение, счётчик записей обнуляется, и начинается перебор. Для каждой записи формируется S-TMSI из идентификатора UE. Если он совпадает с сохранённым у UE и состояние — IDLE, вызывается пейджинг NAS, состояние переводится в ожидание NAS, и шаг повторяется. При несовпадении пишется «Received paging for unknown identity», а в CONNECT — «Received paging while in CONNECT».
Если в сообщении есть признак изменения системной информации, сбрасываются SIB обслуживающей соты и запускается конфигурирование соты заново. Иначе процедура завершается успехом. Событие о завершении пейджинга NAS принимается только в состоянии ожидания NAS: при неуспешном исходе возвращается ошибка, при успешном — счётчик записей увеличивается и перебор продолжается.
Периодическая реселекция в IDLE
При переходе в IDLE запускается таймер сброса RLC, по истечении которого срабатывает переключатель перехода в IDLE. При этом шаг процедуры не вызывается напрямую — комментарий поясняет, что откладывание на один TTI предотвращает повторную блокировку мьютекса RLC.
Периодическая реселекция планируется только если RRC не в соединении и NAS зарегистрирован. При смене соты таймеру задаётся длинный период, иначе — обычный, после чего таймер запускается. Сам таймер настроен так, что по его срабатыванию запускается процедура реселекции и добавляется в список опрашиваемых процедур. При переходе в IDLE реселекция запускается только при отсутствии перенаправления RRC и если NAS зарегистрирован.
Radio Link Failure: три триггера
RLF запускается в трёх случаях: по истечении T310, по индикации проблемы случайного доступа от MAC (когда ни T300, T301, T304, ни T311 не запущены), либо по индикации от RLC о достижении максимума повторных передач.
При обнаружении RLF выводится предупреждение, информация сохраняется в отчёт VarRLF-Report. Если состояние — CONNECTED и безопасность активирована, запускается восстановление соединения с причиной other_fail. Если безопасность деактивирована — переход в IDLE. В остальных состояниях RLF игнорируется.
Индикация проблемы случайного доступа запускает RLF только при условии, что ни один из четырёх таймеров не запущен; иначе индикация игнорируется. Индикация о достижении максимума повторных передач логирует предупреждение и запускает RLF. Индикация отказа протокола RLC только логирует предупреждение, не запуская RLF. Истечение T310 в обработчике таймеров логирует сообщение и запускает RLF.
Восстановление соединения
Процедура восстановления запускается попыткой старта и добавлением в список опрашиваемых процедур. На старте проверяются условия (безопасность активирована, состояние CONNECTED, C-RNTI корректен), сохраняются причина, RNTI, исходные PCI, частота и идентификатор соты. Затем останавливается T310, запускается T311, приостанавливаются все радиоканалы кроме SRB0, сбрасывается MAC, деактивируются SCell, применяются конфигурации PHY и MAC по умолчанию, и запускается выбор соты.
При выборе соты останавливается T311, запускается T301, и запускается выбор с вектором частот {0, 1, 2}. При ошибке ожидается истечение T311. После выбора проверяется, что сота в синхронизации и имеет SIB1, SIB2, SIB3; если нет — выбор запускается повторно. Если сота подходит, проверяются критерии пригодности, и при неудаче выбор снова повторяется. При приёме сообщения о восстановлении останавливается T301, восстанавливаются PDCP и RLC для SRB1, применяется конфигурация и возобновляется SRB1. При истечении T301 или T311, а также при получении отказа восстановления, выполняется переход в IDLE.
Функция остановки всех таймеров останавливает T300, T301, T310, T311 и T304.
Освобождение контекста UE
При получении запроса на освобождение контекста MME сначала проверяет, что запрос пришёл от известной ассоциации eNB, и извлекает MME UE S1AP ID, eNB UE S1AP ID и причину; при неизвестной ассоциации или отсутствии обязательного элемента обработка прекращается с ошибкой. Затем по mme_ue_s1ap_id ищется контекст UE; если он не найден, сообщение игнорируется — MME не знает предоставленный идентификатор.
Если контекст найден и совпадают и ассоциация, и ENB_UE_S1AP_ID, MME отправляет eNB команду освобождения контекста, освободив перед этим туннельные привязки S1-U для всех носителей. Функция удаления устаревшего контекста сама контекст не освобождает — она только формирует и отправляет в MME-приложение сообщение с ENB_UE_S1AP_ID и идентификатором eNB.
При освобождении контекста останавливается таймер освобождения и отправляется уведомление о завершении в MME-приложение. После получения подтверждения от eNB контекст UE удаляется, но только если UE не было передано другому eNB.
Что из этого следует на практике
- Поиск соты и поиск сети — разные процедуры с разной областью действия: первая работает с одной частотой, вторая перебирает частоты. Если телефон «не видит сеть», проблема может быть в переборе частот, а не в самой процедуре поиска соты.
- Неудача чтения SIB1 не считается сбоем поиска соты: сота помечается как не найденная, но процедура возвращает успех. То есть отсутствие SIB1 обрабатывается как «соты нет», а не как ошибка.
- Пригодность соты требует одновременно синхронизации, кампинга, прохождения критерия по RSRP и наличия обязательных SIB. Пока хотя бы одно условие не выполнено, сота не считается пригодной.
- Измерения обрабатываются асинхронно: PHY только кладёт их в очередь и сразу возвращается, а фильтрация и запись в базу идут из потока RRC. Это развязывает быстрый PHY и более медленную обработку.
- Идентификатор UE в запросе соединения может быть либо выданным сетью S-TMSI, либо 40 случайными битами — в зависимости от того, сконфигурирован ли он.
- При хэндовере ключи безопасности обновляются в два этапа: сначала при необходимости на основе свежего KASME, затем всегда — с параметрами целевой соты. При неудаче ключи восстанавливаются из исходной соты.
- RLF запускается только при определённых условиях: индикация проблемы случайного доступа игнорируется, если запущен один из четырёх таймеров, а отказ протокола RLC сам по себе RLF не запускает.
- Пейджинг обрабатывается только при сконфигурированном идентификаторе UE, а совпадение S-TMSI учитывается только в состоянии IDLE — в CONNECT такое сообщение лишь логируется.
- Освобождение контекста UE на MME требует совпадения и ассоциации, и ENB_UE_S1AP_ID; при несовпадении контекст не освобождается, а запрос от неизвестной ассоциации игнорируется.
Где смотреть в коде
- rrc_procedures.cc: then
- rrc_procedures.cc: step
- rrc_procedures.cc: start_phy_cell_selection
- rrc.cc: new_cell_meas
- rrc.cc: radio_link_failure_push_cmd
- rrc_procedures.cc: react
- rrc_procedures.cc: init
- rrc_procedures.cc: go_idle_proc