• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define FAILURE_DEBUG_PREFIX "RadioData"
18 
19 #include <format>
20 #include <string_view>
21 
22 #include <arpa/inet.h>
23 #include <net/if.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26 
27 #include "RadioData.h"
28 
29 #include "debug.h"
30 #include "makeRadioResponseInfo.h"
31 
32 namespace aidl {
33 namespace android {
34 namespace hardware {
35 namespace radio {
36 namespace implementation {
37 using data::DataProfileInfo;
38 using data::PdpProtocolType;
39 using data::SetupDataCallResult;
40 
41 namespace {
42 constexpr char kInterfaceName[] = "eth0";
43 
getProtocolStr(const PdpProtocolType p)44 std::string_view getProtocolStr(const PdpProtocolType p) {
45     using namespace std::literals;
46 
47     switch (p) {
48     case PdpProtocolType::IP: return "IP"sv;
49     case PdpProtocolType::IPV6: return "IPV6"sv;
50     case PdpProtocolType::IPV4V6: return "IPV4V6"sv;
51     case PdpProtocolType::PPP: return "PPP"sv;
52     case PdpProtocolType::NON_IP: return "NON_IP"sv;
53     case PdpProtocolType::UNSTRUCTURED: return "UNSTRUCTURED"sv;
54     default: return {};
55     }
56 }
57 
formatCGDCONT(const int cid,const PdpProtocolType protocol,const std::string_view apn)58 std::string formatCGDCONT(const int cid,
59                           const PdpProtocolType protocol,
60                           const std::string_view apn) {
61     const std::string_view protocolStr = getProtocolStr(protocol);
62     if (protocolStr.empty()) {
63         return FAILURE_V("", "Unexpected protocol: %s", toString(protocol).c_str());
64     }
65 
66     if (apn.empty()) {
67         return FAILURE_V("", "%s", "APN is empty");
68     }
69 
70     return std::format("AT+CGDCONT={0:d},\"{1:s}\",\"{2:s}\",,0,0",
71                        cid, protocolStr, apn);
72 }
73 
setInterfaceState(const char * interfaceName,const bool on)74 bool setInterfaceState(const char* interfaceName, const bool on) {
75     const int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
76     if (sock < 0) {
77         return FAILURE_V(false, "Failed to open interface socket: %s (%d)",
78                          strerror(errno), errno);
79     }
80 
81     struct ifreq request;
82     memset(&request, 0, sizeof(request));
83     strncpy(request.ifr_name, interfaceName, sizeof(request.ifr_name));
84     request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
85 
86     if (ioctl(sock, SIOCGIFFLAGS, &request)) {
87         ::close(sock);
88         return FAILURE_V(false, "Failed to get interface flags for %s: %s (%d)",
89                          interfaceName, strerror(errno), errno);
90     }
91 
92     if (((request.ifr_flags & IFF_UP) != 0) == on) {
93         ::close(sock);
94         return true;  // Interface already in desired state
95     }
96 
97     request.ifr_flags ^= IFF_UP;
98     if (ioctl(sock, SIOCSIFFLAGS, &request)) {
99         ::close(sock);
100         return FAILURE_V(false, "Failed to set interface flags for %s: %s (%d)",
101                          interfaceName, strerror(errno), errno);
102     }
103 
104     ::close(sock);
105     return true;
106 }
107 
setIpAddr(const char * addr,const int addrSize,const char * radioInterfaceName)108 bool setIpAddr(const char *addr, const int addrSize,
109                const char* radioInterfaceName) {
110     const int family = strchr(addr, ':') ? AF_INET6 : AF_INET;
111     const int sock = socket(family, SOCK_DGRAM, 0);
112     if (sock == -1) {
113         return FAILURE_V(false, "Failed to open a %s socket: %s (%d)",
114                          ((family == AF_INET) ? "INET" : "INET6"),
115                          strerror(errno), errno);
116     }
117 
118     struct ifreq req4;
119     memset(&req4, 0, sizeof(req4));
120 
121     strncpy(req4.ifr_name, radioInterfaceName, sizeof(req4.ifr_name));
122     req4.ifr_name[sizeof(req4.ifr_name) - 1] = '\0';
123 
124     if (family == AF_INET) {
125         struct sockaddr_in *sin = (struct sockaddr_in *)&req4.ifr_addr;
126         sin->sin_family = AF_INET;
127         sin->sin_addr.s_addr = inet_addr(addr);
128         if (ioctl(sock, SIOCSIFADDR, &req4) < 0) {
129             ::close(sock);
130             return FAILURE_V(false, "SIOCSIFADDR IPv4 failed: %s (%d)",
131                              strerror(errno), errno);
132         }
133 
134         sin->sin_addr.s_addr = htonl(0xFFFFFFFFu << (32 - (addrSize ? addrSize : 32)));
135         if (ioctl(sock, SIOCSIFNETMASK, &req4) < 0) {
136             ::close(sock);
137             return FAILURE_V(false, "SIOCSIFNETMASK IPv4 failed: %s (%d)",
138                              strerror(errno), errno);
139         }
140     } else {
141         if (ioctl(sock, SIOCGIFINDEX, &req4) < 0) {
142             ::close(sock);
143             return FAILURE_V(false, "SIOCGIFINDEX IPv6 failed: %s (%d)",
144                              strerror(errno), errno);
145         }
146 
147         struct in6_ifreq req6 = {
148             .ifr6_prefixlen = static_cast<__u32>(addrSize ? addrSize : 128),
149             .ifr6_ifindex = req4.ifr_ifindex,
150         };
151 
152         if (inet_pton(AF_INET6, addr, &req6.ifr6_addr) != 1) {
153             ::close(sock);
154             return FAILURE_V(false, "inet_pton(AF_INET6, '%s') failed: %s (%d)",
155                              addr, strerror(errno), errno);
156         }
157 
158         if (ioctl(sock, SIOCSIFADDR, &req6) < 0) {
159             ::close(sock);
160             return FAILURE_V(false, "SIOCSIFADDR failed: %s (%d)",
161                              strerror(errno), errno);
162         }
163     }
164 
165     ::close(sock);
166     return true;
167 }
168 
169 } // namespace
170 
RadioData(std::shared_ptr<AtChannel> atChannel)171 RadioData::RadioData(std::shared_ptr<AtChannel> atChannel) : mAtChannel(std::move(atChannel)) {
172 }
173 
getSlicingConfig(const int32_t serial)174 ScopedAStatus RadioData::getSlicingConfig(const int32_t serial) {
175     // matches reference-ril.c
176     NOT_NULL(mRadioDataResponse)->getSlicingConfigResponse(
177         makeRadioResponseInfo(serial), {});
178     return ScopedAStatus::ok();
179 }
180 
setDataAllowed(const int32_t serial,const bool)181 ScopedAStatus RadioData::setDataAllowed(const int32_t serial,
182                                         const bool /*allow*/) {
183     // matches reference-ril.c
184     NOT_NULL(mRadioDataResponse)->setDataAllowedResponse(
185         makeRadioResponseInfo(serial));
186     return ScopedAStatus::ok();
187 }
188 
setDataProfile(const int32_t serial,const std::vector<DataProfileInfo> &)189 ScopedAStatus RadioData::setDataProfile(const int32_t serial,
190                                         const std::vector<DataProfileInfo>& /*profiles*/) {
191     // matches reference-ril.c
192     NOT_NULL(mRadioDataResponse)->setDataProfileResponse(
193         makeRadioResponseInfo(serial));
194     return ScopedAStatus::ok();
195 }
196 
setDataThrottling(const int32_t serial,const data::DataThrottlingAction,const int64_t)197 ScopedAStatus RadioData::setDataThrottling(const int32_t serial,
198                                            const data::DataThrottlingAction /*dataThrottlingAction*/,
199                                            const int64_t /*completionDurationMillis*/) {
200     // matches reference-ril.c
201     NOT_NULL(mRadioDataResponse)->setDataThrottlingResponse(
202         makeRadioResponseInfo(serial));
203     return ScopedAStatus::ok();
204 }
205 
setInitialAttachApn(const int32_t serial,const std::optional<DataProfileInfo> &)206 ScopedAStatus RadioData::setInitialAttachApn(const int32_t serial,
207                                              const std::optional<DataProfileInfo>& /*maybeDpInfo*/) {
208     // matches reference-ril.c
209     NOT_NULL(mRadioDataResponse)->setInitialAttachApnResponse(
210         makeRadioResponseInfo(serial));
211     return ScopedAStatus::ok();
212 }
213 
allocatePduSessionId(const int32_t serial)214 ScopedAStatus RadioData::allocatePduSessionId(const int32_t serial) {
215     NOT_NULL(mRadioDataResponse)->allocatePduSessionIdResponse(
216         makeRadioResponseInfoUnsupported(  // matches reference-ril.c
217             serial, FAILURE_DEBUG_PREFIX, __func__), 0);
218     return ScopedAStatus::ok();
219 }
220 
releasePduSessionId(const int32_t serial,const int32_t)221 ScopedAStatus RadioData::releasePduSessionId(const int32_t serial,
222                                              const int32_t /*id*/) {
223     NOT_NULL(mRadioDataResponse)->releasePduSessionIdResponse(
224         makeRadioResponseInfo(serial));
225     return ScopedAStatus::ok();
226 }
227 
setupDataCall(const int32_t serial,const AccessNetwork,const DataProfileInfo & dataProfileInfo,const bool,const data::DataRequestReason,const std::vector<data::LinkAddress> &,const std::vector<std::string> &,const int32_t pduSessionId,const std::optional<data::SliceInfo> &,const bool)228 ScopedAStatus RadioData::setupDataCall(const int32_t serial,
229                                        const AccessNetwork /*accessNetwork*/,
230                                        const DataProfileInfo& dataProfileInfo,
231                                        const bool /*roamingAllowed*/,
232                                        const data::DataRequestReason /*reason*/,
233                                        const std::vector<data::LinkAddress>& /*addresses*/,
234                                        const std::vector<std::string>& /*dnses*/,
235                                        const int32_t pduSessionId,
236                                        const std::optional<data::SliceInfo>& /*sliceInfo*/,
237                                        const bool /*matchAllRuleAllowed*/) {
238     if (!setInterfaceState(kInterfaceName, true)) {
239         NOT_NULL(mRadioDataResponse)->setupDataCallResponse(
240                 makeRadioResponseInfo(serial, FAILURE(RadioError::GENERIC_FAILURE)), {});
241         return ScopedAStatus::ok();
242     }
243 
244     static const char* const kFunc = __func__;
245     mAtChannel->queueRequester([this, serial, dataProfileInfo, pduSessionId]
246                                (const AtChannel::RequestPipe requestPipe) -> bool {
247         using CmeError = AtResponse::CmeError;
248         using CGCONTRDP = AtResponse::CGCONTRDP;
249 
250         RadioError status;
251         const int32_t cid = allocateId();
252 
253         std::string request = formatCGDCONT(cid, dataProfileInfo.protocol,
254                                             dataProfileInfo.apn);
255         if (request.empty()) {
256             status = RadioError::INVALID_ARGUMENTS;
257 
258 failed:     releaseId(cid);
259             NOT_NULL(mRadioDataResponse)->setupDataCallResponse(
260                     makeRadioResponseInfo(serial, FAILURE(status)), {});
261             return status != RadioError::INTERNAL_ERR;
262         }
263 
264         AtResponsePtr response =
265             mAtConversation(requestPipe, request,
266                             [](const AtResponse& response) -> bool {
267                                return response.holds<AtResponse::OK>() ||
268                                       response.holds<CmeError>();
269                             });
270         if (!response) {
271             status = FAILURE(RadioError::INTERNAL_ERR);
272             goto failed;
273         } else if (const CmeError* err = response->get_if<CmeError>()) {
274             status = FAILURE_V(err->error, "%s",  toString(err->error).c_str());
275             goto failed;
276         } else if (!response->holds<AtResponse::OK>()) {
277             response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
278         }
279 
280         SetupDataCallResult setupDataCallResult = {
281             .suggestedRetryTime = -1,
282             .cid = cid,
283             .active = SetupDataCallResult::DATA_CONNECTION_STATUS_ACTIVE,
284             .type = dataProfileInfo.protocol,
285             .ifname = kInterfaceName,
286             .mtuV4 = 1500,
287             .mtuV6 = 1500,
288             .handoverFailureMode = SetupDataCallResult::HANDOVER_FAILURE_MODE_LEGACY,
289             .pduSessionId = pduSessionId,
290         };
291 
292         request = std::format("AT+CGCONTRDP={0:d}", cid);
293         response =
294             mAtConversation(requestPipe, request,
295                             [](const AtResponse& response) -> bool {
296                                return response.holds<CGCONTRDP>() ||
297                                       response.holds<CmeError>();
298                             });
299         if (!response || response->isParseError()) {
300             status = FAILURE(RadioError::INTERNAL_ERR);
301             goto failed;
302         } else if (const CGCONTRDP* cgcontrdp = response->get_if<CGCONTRDP>()) {
303             if (!setIpAddr(cgcontrdp->localAddr.c_str(),
304                            cgcontrdp->localAddrSize,
305                            setupDataCallResult.ifname.c_str())) {
306                 status = FAILURE(RadioError::GENERIC_FAILURE);
307                 goto failed;
308             }
309 
310             const auto makeLinkAddress = [](const std::string_view address,
311                                             const size_t addrSize) -> data::LinkAddress {
312                 return {
313                     .address = std::format("{0:s}/{1:d}", address, addrSize),
314                     .addressProperties = 0,
315                     .deprecationTime = -1,
316                     .expirationTime = -1,
317                 };
318             };
319 
320             setupDataCallResult.addresses.push_back(
321                 makeLinkAddress(cgcontrdp->localAddr, cgcontrdp->localAddrSize));
322             setupDataCallResult.gateways.push_back(cgcontrdp->gwAddr);
323             setupDataCallResult.dnses.push_back(cgcontrdp->dns1);
324             if (!cgcontrdp->dns2.empty()) {
325                 setupDataCallResult.dnses.push_back(cgcontrdp->dns2);
326             }
327 
328             std::lock_guard<std::mutex> lock(mMtx);
329             mDataCalls.insert({ cid, setupDataCallResult });
330             status = RadioError::NONE;
331         } else if (const CmeError* err = response->get_if<CmeError>()) {
332             status = FAILURE_V(err->error, "%s",  toString(err->error).c_str());
333             goto failed;
334         } else {
335             response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
336         }
337 
338         NOT_NULL(mRadioDataResponse)->setupDataCallResponse(
339             makeRadioResponseInfo(serial), std::move(setupDataCallResult));
340 
341         NOT_NULL(mRadioDataIndication)->dataCallListChanged(
342             RadioIndicationType::UNSOLICITED, getDataCalls());
343         return true;
344     });
345 
346     return ScopedAStatus::ok();
347 }
348 
deactivateDataCall(const int32_t serial,const int32_t cid,const data::DataRequestReason)349 ScopedAStatus RadioData::deactivateDataCall(
350         const int32_t serial, const int32_t cid,
351         const data::DataRequestReason /*reason*/) {
352     bool removed;
353     bool empty;
354     {
355         std::lock_guard<std::mutex> lock(mMtx);
356         const auto i = mDataCalls.find(cid);
357         if (i != mDataCalls.end()) {
358             mDataCalls.erase(i);
359             mIdAllocator.put(cid);
360             removed = true;
361         } else {
362             removed = false;
363         }
364         empty = mDataCalls.empty();
365     }
366 
367     if (empty) {
368         setInterfaceState(kInterfaceName, false);
369     }
370 
371     if (removed) {
372         NOT_NULL(mRadioDataResponse)->deactivateDataCallResponse(
373             makeRadioResponseInfo(serial));
374 
375         NOT_NULL(mRadioDataIndication)->dataCallListChanged(
376             RadioIndicationType::UNSOLICITED, getDataCalls());
377     } else {
378         NOT_NULL(mRadioDataResponse)->deactivateDataCallResponse(
379             makeRadioResponseInfo(serial, FAILURE(RadioError::INVALID_ARGUMENTS)));
380     }
381 
382     return ScopedAStatus::ok();
383 }
384 
getDataCallList(const int32_t serial)385 ScopedAStatus RadioData::getDataCallList(const int32_t serial) {
386     NOT_NULL(mRadioDataResponse)->getDataCallListResponse(
387         makeRadioResponseInfo(serial), getDataCalls());
388     return ScopedAStatus::ok();
389 }
390 
startHandover(const int32_t serial,const int32_t)391 ScopedAStatus RadioData::startHandover(const int32_t serial,
392                                        const int32_t /*callId*/) {
393     NOT_NULL(mRadioDataResponse)->startHandoverResponse(
394         makeRadioResponseInfoUnsupported(  // matches reference-ril.c
395             serial, FAILURE_DEBUG_PREFIX, __func__));
396     return ScopedAStatus::ok();
397 }
398 
cancelHandover(const int32_t serial,const int32_t)399 ScopedAStatus RadioData::cancelHandover(const int32_t serial,
400                                         const int32_t /*callId*/) {
401     NOT_NULL(mRadioDataResponse)->cancelHandoverResponse(
402         makeRadioResponseInfoUnsupported(  // matches reference-ril.c
403             serial, FAILURE_DEBUG_PREFIX, __func__));
404     return ScopedAStatus::ok();
405 }
406 
startKeepalive(const int32_t serial,const data::KeepaliveRequest &)407 ScopedAStatus RadioData::startKeepalive(const int32_t serial,
408                                         const data::KeepaliveRequest& /*keepalive*/) {
409     const int32_t sessionHandle = allocateId();
410 
411     {
412         std::lock_guard<std::mutex> lock(mMtx);
413         mKeepAliveSessions.insert(sessionHandle);
414     }
415 
416     using data::KeepaliveStatus;
417 
418     KeepaliveStatus keepaliveStatus = {
419         .sessionHandle = sessionHandle,
420         .code = KeepaliveStatus::CODE_ACTIVE,
421     };
422 
423     NOT_NULL(mRadioDataResponse)->startKeepaliveResponse(
424         makeRadioResponseInfo(serial), std::move(keepaliveStatus));
425     return ScopedAStatus::ok();
426 }
427 
stopKeepalive(const int32_t serial,const int32_t sessionHandle)428 ScopedAStatus RadioData::stopKeepalive(const int32_t serial,
429                                        const int32_t sessionHandle) {
430     bool removed;
431     {
432         std::lock_guard<std::mutex> lock(mMtx);
433         removed = mKeepAliveSessions.erase(sessionHandle) > 0;
434     }
435 
436     if (removed) {
437         releaseId(sessionHandle);
438     }
439 
440     NOT_NULL(mRadioDataResponse)->stopKeepaliveResponse(
441         makeRadioResponseInfo(serial, removed ?
442             RadioError::NONE : FAILURE(RadioError::INVALID_ARGUMENTS)));
443     return ScopedAStatus::ok();
444 }
445 
responseAcknowledgement()446 ScopedAStatus RadioData::responseAcknowledgement() {
447     return ScopedAStatus::ok();
448 }
449 
atResponseSink(const AtResponsePtr & response)450 void RadioData::atResponseSink(const AtResponsePtr& response) {
451     if (!mAtConversation.send(response)) {
452         response->visit([this](const auto& msg){ handleUnsolicited(msg); });
453     }
454 }
455 
setResponseFunctions(const std::shared_ptr<data::IRadioDataResponse> & radioDataResponse,const std::shared_ptr<data::IRadioDataIndication> & radioDataIndication)456 ScopedAStatus RadioData::setResponseFunctions(
457         const std::shared_ptr<data::IRadioDataResponse>& radioDataResponse,
458         const std::shared_ptr<data::IRadioDataIndication>& radioDataIndication) {
459     mRadioDataResponse = NOT_NULL(radioDataResponse);
460     mRadioDataIndication = NOT_NULL(radioDataIndication);
461     return ScopedAStatus::ok();
462 }
463 
allocateId()464 int32_t RadioData::allocateId() {
465     std::lock_guard<std::mutex> lock(mMtx);
466     return mIdAllocator.get();
467 }
468 
releaseId(const int32_t cid)469 void RadioData::releaseId(const int32_t cid) {
470     std::lock_guard<std::mutex> lock(mMtx);
471     mIdAllocator.put(cid);
472 }
473 
getDataCalls() const474 std::vector<SetupDataCallResult> RadioData::getDataCalls() const {
475     std::vector<SetupDataCallResult> dataCalls;
476 
477     std::lock_guard<std::mutex> lock(mMtx);
478     for (const auto& kv : mDataCalls) {
479         dataCalls.push_back(kv.second);
480     }
481 
482     return dataCalls;
483 }
484 
485 }  // namespace implementation
486 }  // namespace radio
487 }  // namespace hardware
488 }  // namespace android
489 }  // namespace aidl
490