Skip to content

Commit

Permalink
Cellular fix to PPP only: recover from service denial.
Browse files Browse the repository at this point in the history
If either the network or the cellular module causes the PDP context to be deactivated while a PPP connection is active, that PPP connection will be deactivated by the cellular module sending an LCP Terminate Request over the PPP interface to the peer entity.  At this point the PPP connection is dead, it will never be reactivated ever, and so when the PDP context comes back the inactive connection needs to be torn down and a new one brought up,

Test: 23.0 networkOutage
  • Loading branch information
RobMeades committed Sep 17, 2024
1 parent 7dd4206 commit 566a0e3
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 7 deletions.
60 changes: 53 additions & 7 deletions cell/src/u_cell_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ static const uCellNetRegDomain_t gRegTypeToDomain[] = {
U_CELL_NET_REG_DOMAIN_PS, // U_CELL_PRIVATE_NET_REG_TYPE_CGREG
U_CELL_NET_REG_DOMAIN_PS // U_CELL_PRIVATE_NET_REG_TYPE_CEREG
};

#if U_CFG_ENABLE_LOGGING
/** Strings that describe the possible authentication modes;
* used in a debug print only, MUST have the same number of
Expand All @@ -215,6 +216,13 @@ static const char *gpAuthenticationModeStr[] = {
};
#endif

/** The [start of] strings returned by +CGEV which mean that
* the PDP context has been removed unexpectedly by the network.
*/
static const char *gpCgevPdpContextFailure[] = {
"NW PDN DEACT", "NW DETACH"
};

/* ----------------------------------------------------------------
* STATIC FUNCTIONS: FORWARD DECLARATIONS
* -------------------------------------------------------------- */
Expand Down Expand Up @@ -725,22 +733,58 @@ static void CSCON_urc(uAtClientHandle_t atHandle, void *pParameter)
}
}

// Take action on a PDP context being deactivated by the network/module,
// which will be signalled by a +UUPSDD or +CGEV URC.
static void contextDeactivated(uCellPrivateInstance_t *pInstance)
{
if (pInstance->profileState == U_CELL_PRIVATE_PROFILE_STATE_SHOULD_BE_UP) {
// Set the state so that, should we re-register with the network,
// we will reactivate the internal profile
pInstance->profileState = U_CELL_PRIVATE_PROFILE_STATE_REQUIRES_REACTIVATION;
}
}

// Detect a change in the state of context activation
static void CGEV_urc(uAtClientHandle_t atHandle, void *pParameter)
{
uCellPrivateInstance_t *pInstance = (uCellPrivateInstance_t *) pParameter;
char buffer[32];
int32_t x;
bool pdpContextFailure = false;
int32_t failureStringLength;

x = uAtClientReadString(atHandle, buffer, sizeof(buffer), false);

// The +CGEV URCs of interest are the ones that indicate a context
// has been deactivated, which are:
//
// NW PDN DEACT <cid>
// NW DETACH

for (size_t y = 0; !pdpContextFailure && (x > 0) &&
(y < sizeof(gpCgevPdpContextFailure) /
sizeof(gpCgevPdpContextFailure[0])); y++) {
failureStringLength = strlen(gpCgevPdpContextFailure[y]);
pdpContextFailure = (x >= failureStringLength) &&
(memcmp(buffer, gpCgevPdpContextFailure[y], failureStringLength) == 0);
}

if (pdpContextFailure) {
contextDeactivated(pInstance);
}
}

// Detect deactivation of an internal profile, which will occur if we
// fall out of service.
static void UUPSDD_urc(uAtClientHandle_t atHandle,
void *pParameter)
static void UUPSDD_urc(uAtClientHandle_t atHandle, void *pParameter)
{
uCellPrivateInstance_t *pInstance = (uCellPrivateInstance_t *) pParameter;

// Skip the parameter; we don't care since we only ever
// activate a single internal profile
uAtClientSkipParameters(atHandle, 1);

if (pInstance->profileState == U_CELL_PRIVATE_PROFILE_STATE_SHOULD_BE_UP) {
// Set the state so that, should we re-register with the network,
// we will reactivate the internal profile
pInstance->profileState = U_CELL_PRIVATE_PROFILE_STATE_REQUIRES_REACTIVATION;
}
contextDeactivated(pInstance);
}

/* ----------------------------------------------------------------
Expand Down Expand Up @@ -827,6 +871,7 @@ static int32_t prepareConnect(uCellPrivateInstance_t *pInstance)
uAtClientSetUrcHandler(atHandle, "+CGREG:", CGREG_urc, pInstance);
uAtClientSetUrcHandler(atHandle, "+CEREG:", CEREG_urc, pInstance);
uAtClientSetUrcHandler(atHandle, "+UUPSDD:", UUPSDD_urc, pInstance);
uAtClientSetUrcHandler(atHandle, "+CGEV:", CGEV_urc, pInstance);

// Switch on the unsolicited result codes for registration
// and also ask for the additional parameters <lac>, <ci> and
Expand Down Expand Up @@ -2401,6 +2446,7 @@ static int32_t disconnect(uCellPrivateInstance_t *pInstance,
uAtClientRemoveUrcHandler(atHandle, "+CGREG:");
uAtClientRemoveUrcHandler(atHandle, "+CEREG:");
uAtClientRemoveUrcHandler(atHandle, "+UUPSDD:");
uAtClientRemoveUrcHandler(atHandle, "+CGEV:");
uPortLog("U_CELL_NET: disconnected.\n");
} else {
uPortLog("U_CELL_NET: unable to disconnect.\n");
Expand Down
6 changes: 6 additions & 0 deletions port/platform/esp-idf/src/u_port_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ static void eventIpChanged(void *pArgs, esp_event_base_t eventBase,
uPortPppNetifDriver_t *pDriver = (uPortPppNetifDriver_t *) pArgs;
struct uPortPppInterface_t *pPppInterface = pDriver->pPppInterface;

uPortLog("U_PORT_PPP: received IP event %d.\n", eventId);
switch (eventId) {
case IP_EVENT_PPP_GOT_IP:
pPppInterface->ipConnected = true;
Expand Down Expand Up @@ -689,6 +690,11 @@ int32_t uPortPppReconnect(void *pDevHandle,
pEspNetif = pPppInterface->netifDriver.base.netif;
if ((pEspNetif != NULL) && (setIpAddress(pEspNetif, pIpAddress) == ESP_OK)) {
errorCode = (int32_t) U_ERROR_COMMON_SUCCESS;
// Perform a disconnect and then connect again
if (pPppInterface->pDisconnectCallback != NULL) {
pPppInterface->pDisconnectCallback(pPppInterface->pDevHandle,
pPppInterface->ipConnected);
}
if (pPppInterface->pConnectCallback != NULL) {
errorCode = pPppInterface->pConnectCallback(pDevHandle, receiveCallback,
&(pPppInterface->netifDriver),
Expand Down

0 comments on commit 566a0e3

Please sign in to comment.