Skip to content

Commit 9f05f7f

Browse files
milan-zededaclaude
authored andcommitted
mmdbus: improve eSIM detection using EID and handle missing slot paths
Without proper eSIM detection, EVE cannot identify that the active slot is an eSIM and remains stuck on the unsupported eSIM slot instead of automatically switching to a physical SIM slot. ModemManager often fails to report SIM slot types (SIMPropertyType returns "unknown"/unspecified), making it impossible to distinguish eSIM from physical SIM. Improve detection by querying the EID (eUICC Identifier) — only eSIM chips carry one, so its presence reliably identifies an eSIM. Additionally, ModemPropertySIMSlots returns empty D-Bus paths for slots with no SIM or no active eSIM profile. For the currently active slot, fall back to ModemPropertySIM which often still provides a valid object even when the slot array entry is empty. Unify SIM presence detection for unknown and physical SIM types: use the slot array path (hasSlotPath) as the common presence indicator instead of checking ICCID for unknown types separately. In preferPhysSimOverESim, prefer a confirmed physical slot over an unspecified-type candidate. When the active slot is a detected eSIM, it is very unlikely for a modem to have multiple eUICCs, so the remaining slots with unknown type are almost certainly physical — but only used as a fallback. Signed-off-by: Milan Lenco <milan@zededa.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6719f91 commit 9f05f7f

File tree

2 files changed

+62
-27
lines changed

2 files changed

+62
-27
lines changed

pkg/wwan/mmagent/mmdbus/client.go

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,23 @@ func (c *Client) getModemStatus(modemObj dbus.BusObject) (
553553
for i, simPath := range simSlots {
554554
slot := uint8(i + 1)
555555
isPrimary := uint32(slot) == primarySIM
556+
// ModemPropertySIMSlots returns empty (root "/") D-Bus paths for slots
557+
// with no SIM inserted or no active eSIM profile. Record whether the slot
558+
// had a valid path before we attempt the fallback below.
559+
hasSlotPath := simPath.IsValid() && len(simPath) > 1
556560
simCard := types.WwanSimCard{
557561
SlotNumber: slot,
558562
SlotActivated: isPrimary,
559563
Type: types.SimTypeUnspecified,
560564
State: SIMStateAbsent,
561565
}
566+
// ModemPropertySIMSlots may return an empty path for the active slot
567+
// (e.g. eSIM with no profile), but ModemPropertySIM often still provides
568+
// a valid object. Fall back to it so we can query SIM properties (EID,
569+
// ICCID, etc.) for the active slot even when the slot array is incomplete.
570+
if isPrimary && !hasSlotPath {
571+
_ = getDBusProperty(c, modemObj, ModemPropertySIM, &simPath)
572+
}
562573
if simPath.IsValid() && len(simPath) > 1 {
563574
simPaths = append(simPaths, string(simPath))
564575
simObj := c.conn.Object(MMInterface, simPath)
@@ -568,31 +579,27 @@ func (c *Client) getModemStatus(modemObj dbus.BusObject) (
568579
_ = getDBusProperty(c, simObj, SIMPropertyIMSI, &simCard.IMSI)
569580
var simType uint32
570581
_ = getDBusProperty(c, simObj, SIMPropertyType, &simType)
582+
// ModemManager often reports SIMPropertyType as "unknown" even for
583+
// eSIMs. Improve detection by checking for an EID (eUICC Identifier).
584+
// Only eSIM chips have one, so its presence is a reliable indicator.
585+
var eid string
586+
_ = getDBusProperty(c, simObj, SIMPropertyEID, &eid)
587+
if simType == SIMTypeUnknown && eid != "" {
588+
simType = SIMTypeESIM
589+
}
571590
switch simType {
572-
case SIMTypeUnknown:
573-
// If the SIM type is not recognized, consider SIM card as present
574-
// if ICCID is not empty.
575-
if simCard.ICCID != "" {
576-
simCard.State = SIMStatePresent
577-
}
578-
case SIMTypeESIM:
579-
// eSIM is not supported by EVE (or even by ModemManager) for connection
580-
// establishment, but we still want to at least publish correct status
581-
// information for the eSIM "slot".
582-
simCard.Type = types.SimTypeEmbedded
583-
var esimStatus uint32
584-
_ = getDBusProperty(c, simObj, SIMPropertyESIMStatus, &esimStatus)
585-
if esimStatus == ESIMWithProfiles {
586-
simCard.State = SIMStatePresent
587-
}
588-
case SIMTypePhysical:
589-
// Since we have valid dbus object for the physical SIM slot, it means
590-
// that the SIM card is present.
591-
// But note that even if SIM card is present but the slot is inactive,
592-
// ModemManager might report the card as absent, without providing any SIM
593-
// object path to work with.
594-
// On the other hand, with mbimcli we are able to distinguish between
595-
// missing and inactive SIM card:
591+
case SIMTypeUnknown, SIMTypePhysical:
592+
// For both unknown and physical SIM types, use the presence of
593+
// a valid D-Bus path in the slot array (hasSlotPath) as the
594+
// indicator of SIM card presence.
595+
// Note: for the primary slot we may have obtained the path via
596+
// the ModemPropertySIM fallback above, not from the slot array.
597+
// In that case hasSlotPath is false, indicating empty SIM slot.
598+
//
599+
// However, for inactive slots, ModemManager may not provide any SIM
600+
// object path even if a card is physically inserted.
601+
// With mbimcli we are able to distinguish between missing and
602+
// inactive SIM card:
596603
// mbimcli -p -d /dev/cdc-wdm0 --ms-query-slot-info-status 0
597604
// [/dev/cdc-wdm0] Slot info status retrieved:
598605
// Slot '0': 'state-off'
@@ -616,8 +623,22 @@ func (c *Client) getModemStatus(modemObj dbus.BusObject) (
616623
// Num apps: 0
617624
// Is eUICC: no
618625
// TODO: should we call mbimcli/qmicli ?
619-
simCard.Type = types.SimTypePhysical
620-
simCard.State = SIMStatePresent
626+
if simType == SIMTypePhysical {
627+
simCard.Type = types.SimTypePhysical
628+
}
629+
if hasSlotPath {
630+
simCard.State = SIMStatePresent
631+
}
632+
case SIMTypeESIM:
633+
// eSIM is not supported by EVE (or even by ModemManager) for connection
634+
// establishment, but we still want to at least publish correct status
635+
// information for the eSIM "slot".
636+
simCard.Type = types.SimTypeEmbedded
637+
var esimStatus uint32
638+
_ = getDBusProperty(c, simObj, SIMPropertyESIMStatus, &esimStatus)
639+
if esimStatus == ESIMWithProfiles {
640+
simCard.State = SIMStatePresent
641+
}
621642
}
622643
if !simCard.SlotActivated {
623644
simCard.State = SIMStateInactive
@@ -1623,19 +1644,32 @@ func (c *Client) preferPhysSimOverESim(modemObj dbus.BusObject) error {
16231644
return fmt.Errorf("missing SIM card status for modem: %s", modem.Path)
16241645
}
16251646
var usesESim bool
1626-
var firstPhysSlot uint8 // slots starts with 1 (0 can be used as undefined)
1647+
var firstPhysSlot uint8 // first confirmed physical slot (0 = none found)
1648+
var firstCandidatePhysSlot uint8 // first unspecified-type slot (0 = none found)
16271649
for _, simCard := range modem.Status.SimCards {
16281650
switch simCard.Type {
16291651
case types.SimTypePhysical:
16301652
if firstPhysSlot == 0 || simCard.SlotNumber < firstPhysSlot {
16311653
firstPhysSlot = simCard.SlotNumber
16321654
}
1655+
case types.SimTypeUnspecified:
1656+
// When the active slot is eSIM, ModemManager often fails to report
1657+
// types for inactive slots (returns "unknown"). It is very unlikely
1658+
// for a modem to have multiple eUICCs, so assuming that the other
1659+
// slots are physical is a safe bet. However, prefer a confirmed
1660+
// physical slot if one is available.
1661+
if firstCandidatePhysSlot == 0 || simCard.SlotNumber < firstCandidatePhysSlot {
1662+
firstCandidatePhysSlot = simCard.SlotNumber
1663+
}
16331664
case types.SimTypeEmbedded:
16341665
if simCard.SlotActivated {
16351666
usesESim = true
16361667
}
16371668
}
16381669
}
1670+
if firstPhysSlot == 0 {
1671+
firstPhysSlot = firstCandidatePhysSlot
1672+
}
16391673
if !usesESim || firstPhysSlot == 0 {
16401674
// Nothing to do.
16411675
return nil

pkg/wwan/mmagent/mmdbus/mmapi.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const (
6363
SIMPropertyIMSI = SIMInterface + ".Imsi"
6464
SIMPropertyType = SIMInterface + ".SimType"
6565
SIMPropertyESIMStatus = SIMInterface + ".EsimStatus"
66+
SIMPropertyEID = SIMInterface + ".Eid"
6667
)
6768

6869
// SIM type

0 commit comments

Comments
 (0)