diff mbox series

[OpenWrt-Devel,v3] uqmi: allow matching IMSI for qmi networks

Message ID 20181104234553.GA6732@makrotopia.org
State Deferred
Headers show
Series [OpenWrt-Devel,v3] uqmi: allow matching IMSI for qmi networks | expand

Commit Message

Daniel Golle Nov. 4, 2018, 11:46 p.m. UTC
Introduce 'imsi' configuration option for proto 'qmi' network
interfaces. Setting it makes sure the configuration only gets used
on the intended SIM card. In this way, one can have many configurations
for different SIM cards selected automatically when the card was either
swapped physically or in software (as possible on the APU3 board).
In order to allow multiple configurations using the same character
device, add locking in netifd protocol handler to avoid overlapping
execution of uqmi of the same device.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
 package/network/utils/uqmi/Makefile           |  2 +-
 .../utils/uqmi/files/lib/netifd/proto/qmi.sh  | 54 ++++++++++++++++---
 2 files changed, 49 insertions(+), 7 deletions(-)

Comments

Piotr Dymacz Nov. 5, 2018, 11:28 a.m. UTC | #1
Hi Daniel,

On 05.11.2018 00:46, Daniel Golle wrote:
> Introduce 'imsi' configuration option for proto 'qmi' network
> interfaces. Setting it makes sure the configuration only gets used
> on the intended SIM card. In this way, one can have many configurations
> for different SIM cards selected automatically when the card was either
> swapped physically or in software (as possible on the APU3 board).
> In order to allow multiple configurations using the same character
> device, add locking in netifd protocol handler to avoid overlapping
> execution of uqmi of the same device.

As the general idea seems correct, I find it very limited and maybe 
problematic (is IMSI number always available before SIM is unlocked?). 
Personally, I would prefer to introduce a generic/universal solution, 
not limited to any of the wwan protocols.

I've been using for years slightly different approach which, in the same 
or modified version, might suit better than your idea, also in multi-SIM 
and/or multi-modem solutions or for users often changing SIM cards in a 
single device. Let me try to explain the idea below.

Instead of keeping SIM/operator related configuration (apn, pincode...) 
within the modem network configuration section (glued to a specific 
interface), we introduce a generic 'sim' config file (/etc/config/sim), 
as part of the wwan package, which by default contains only one, default 
configuration (no pin, no auth, generic apn, lets say: 'internet'). If 
the user wants to setup additional _SIM-specific_ configuration, section 
should be named with the SIM ICCID number, for example:

config sim
   option apn 'internet'

...

config sim '1234567890ABCDEFGHI'
   option apn 'internet6'
   option pincode '0000'
   option auth 'PAP'
   option username 'user'
   option password 'pass'

...

SIM ICCID is known to the user (operators print it on the SIM itself) 
and available for the software in advance, even before pin-unlocking.

Essentially, this idea maps whole or almost whole configuration required 
for Internet access to SIM, instead of the modem (or, device interface 
in system). During interface setup/bring-up, SIM configuration is 
searched for a specific section (based on the ICCID of the SIM in use) 
and in case it's missing, default one is used.

Of course, this approach requires all available wwan protocols to 
support fetching ICCID from the SIM and also inform the user about 
missing SIM-specific configuration if it's required (SIM requires PIN 
but SIM-specific configuration is missing).
Plus, some kind of migration mechanism would be required for current 
solution (SIM configuration in network config file).
Daniel Golle Nov. 5, 2018, 3:21 p.m. UTC | #2
Hi Piotr,

On Mon, Nov 05, 2018 at 12:28:06PM +0100, Piotr Dymacz wrote:
> Hi Daniel,
> 
> On 05.11.2018 00:46, Daniel Golle wrote:
> > Introduce 'imsi' configuration option for proto 'qmi' network
> > interfaces. Setting it makes sure the configuration only gets used
> > on the intended SIM card. In this way, one can have many configurations
> > for different SIM cards selected automatically when the card was either
> > swapped physically or in software (as possible on the APU3 board).
> > In order to allow multiple configurations using the same character
> > device, add locking in netifd protocol handler to avoid overlapping
> > execution of uqmi of the same device.
> 
> As the general idea seems correct, I find it very limited and maybe
> problematic (is IMSI number always available before SIM is unlocked?).

I also realized that it not always is available after a power-cycle,
but it seems to be available before unlocking... If the ICCID is
always available, then that'd solve the problem.

> Personally, I would prefer to introduce a generic/universal solution, not
> limited to any of the wwan protocols.

I agree.

> 
> I've been using for years slightly different approach which, in the same or
> modified version, might suit better than your idea, also in multi-SIM and/or
> multi-modem solutions or for users often changing SIM cards in a single
> device. Let me try to explain the idea below.
> 
> Instead of keeping SIM/operator related configuration (apn, pincode...)
> within the modem network configuration section (glued to a specific
> interface), we introduce a generic 'sim' config file (/etc/config/sim), as
> part of the wwan package, which by default contains only one, default
> configuration (no pin, no auth, generic apn, lets say: 'internet'). If the
> user wants to setup additional _SIM-specific_ configuration, section should
> be named with the SIM ICCID number, for example:
> 
> config sim
>   option apn 'internet'
> 
> ...
> 
> config sim '1234567890ABCDEFGHI'
>   option apn 'internet6'
>   option pincode '0000'
>   option auth 'PAP'
>   option username 'user'
>   option password 'pass'
> 
> ...

I'd kinda like to see the option of all interface parameters being
inherited from a sim-specific configuration. I got things like ip4table
or peerdns in mind here which would also be useful in my setups.

> 
> SIM ICCID is known to the user (operators print it on the SIM itself) and
> available for the software in advance, even before pin-unlocking.
> 
> Essentially, this idea maps whole or almost whole configuration required for
> Internet access to SIM, instead of the modem (or, device interface in
> system). During interface setup/bring-up, SIM configuration is searched for
> a specific section (based on the ICCID of the SIM in use) and in case it's
> missing, default one is used.
> 
> Of course, this approach requires all available wwan protocols to support
> fetching ICCID from the SIM and also inform the user about missing
> SIM-specific configuration if it's required (SIM requires PIN but
> SIM-specific configuration is missing).
> Plus, some kind of migration mechanism would be required for current
> solution (SIM configuration in network config file).

I like that idea a lot. Seems like we'll need uqmid or a full-blown
ModemManager-replacement for that. Or let netifd have protocol 'probe'
callback (which would be nice to have also eg. for PPPoE) querying WAN
devices' properties (like the name of the Access Concentrator in case
of PPPoE or the ICCID in case of a device holding a SIM card) and
have netifd manage the state.
wwan protocols would have to implement that 'probe' callback returning
available devices and properties. This could also be called upon
hotplug events now taken care of by /etc/hotplug.d/tty/30-3g (and that
looks like it'd need some polishing to work well with mbim and qmi
modems).

Generally, it'd even be useful to untangle this from network interface
configuration, so that a modem can be used for other things as well
such as sending/receiving SMS and network selection/registration, and
in future maybe making Voice, Location, Firmware, ... functions
available via ubus. Hence I see the need for a general debate on
whether modem detection/configuration/... should entirely happen in
netifd (I like the idea because there is no need for an additional
process) via additional proto callbacks or if we should have an
external ModemManager-like daemon.


Cheers


Daniel




> 
> -- 
> Cheers,
> Piotr
> 
> > 
> > Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> > ---
> >   package/network/utils/uqmi/Makefile           |  2 +-
> >   .../utils/uqmi/files/lib/netifd/proto/qmi.sh  | 54 ++++++++++++++++---
> >   2 files changed, 49 insertions(+), 7 deletions(-)
> > 
> > diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile
> > index b2f3474400..8eaf0bff3f 100644
> > --- a/package/network/utils/uqmi/Makefile
> > +++ b/package/network/utils/uqmi/Makefile
> > @@ -1,7 +1,7 @@
> >   include $(TOPDIR)/rules.mk
> >   PKG_NAME:=uqmi
> > -PKG_RELEASE:=5
> > +PKG_RELEASE:=6
> >   PKG_SOURCE_PROTO:=git
> >   PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git
> > diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
> > index 9b2f69f009..2edbe7c28e 100755
> > --- a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
> > +++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
> > @@ -10,6 +10,7 @@ proto_qmi_init_config() {
> >   	available=1
> >   	no_device=1
> >   	proto_config_add_string "device:device"
> > +	proto_config_add_string imsi
> >   	proto_config_add_string apn
> >   	proto_config_add_string auth
> >   	proto_config_add_string username
> > @@ -28,12 +29,12 @@ proto_qmi_init_config() {
> >   proto_qmi_setup() {
> >   	local interface="$1"
> > -	local dataformat connstat
> > -	local device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn timeout $PROTO_DEFAULT_OPTIONS
> > +	local dataformat connstat imsi_actual
> > +	local device imsi apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn timeout $PROTO_DEFAULT_OPTIONS
> >   	local ip4table ip6table
> >   	local cid_4 pdh_4 cid_6 pdh_6
> >   	local ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
> > -	json_get_vars device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn ip4table ip6table timeout $PROTO_DEFAULT_OPTIONS
> > +	json_get_vars device imsi apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn ip4table ip6table timeout $PROTO_DEFAULT_OPTIONS
> >   	[ "$timeout" = "" ] && timeout="10"
> > @@ -68,10 +69,16 @@ proto_qmi_setup() {
> >   		return 1
> >   	}
> > +	lockname="/var/lock/LCK..$devname"
> > +	lock "$lockname"
> > +
> >   	echo "Waiting for SIM initialization"
> >   	local uninitialized_timeout=0
> >   	while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
> > -		[ -e "$device" ] || return 1
> > +		[ -e "$device" ] || {
> > +			lock -u "$lockname"
> > +			return 1
> > +		}
> >   		if [ "$uninitialized_timeout" -lt "$timeout" ]; then
> >   			let uninitialized_timeout++
> >   			sleep 1;
> > @@ -79,16 +86,29 @@ proto_qmi_setup() {
> >   			echo "SIM not initialized"
> >   			proto_notify_error "$interface" SIM_NOT_INITIALIZED
> >   			proto_block_restart "$interface"
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> >   	done
> > +	[ -n "$imsi" ] && {
> > +		imsi_actual="$(uqmi -s -d "$device" --get-imsi | cut -d'"' -f2)"
> > +		[ "$imsi" = "$imsi_actual" ] || {
> > +			echo "Configured IMSI doesn't match SIM card."
> > +			proto_notify_error "$interface" SIM_WRONG
> > +			proto_set_available "$interface" 0
> > +			lock -u "$lockname"
> > +			return 1
> > +		}
> > +	}
> > +
> >   	if uqmi -s -d "$device" --get-pin-status | grep '"Not supported"' > /dev/null; then
> >   		[ -n "$pincode" ] && {
> >   			uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null || {
> >   				echo "Unable to verify PIN"
> >   				proto_notify_error "$interface" PIN_FAILED
> >   				proto_block_restart "$interface"
> > +				lock -u "$lockname"
> >   				return 1
> >   			}
> >   		}
> > @@ -106,6 +126,7 @@ proto_qmi_setup() {
> >   				echo "SIM locked PUK required"
> >   				proto_notify_error "$interface" PUK_NEEDED
> >   				proto_block_restart "$interface"
> > +				lock -u "$lockname"
> >   				return 1
> >   				;;
> >   			not_verified)
> > @@ -113,6 +134,7 @@ proto_qmi_setup() {
> >   					echo "PIN verify count value is $pin1_verify_tries this is below the limit of 3"
> >   					proto_notify_error "$interface" PIN_TRIES_BELOW_LIMIT
> >   					proto_block_restart "$interface"
> > +					lock -u "$lockname"
> >   					return 1
> >   				}
> >   				if [ -n "$pincode" ]; then
> > @@ -120,12 +142,14 @@ proto_qmi_setup() {
> >   						echo "Unable to verify PIN"
> >   						proto_notify_error "$interface" PIN_FAILED
> >   						proto_block_restart "$interface"
> > +						lock -u "$lockname"
> >   						return 1
> >   					}
> >   				else
> >   					echo "PIN not specified but required"
> >   					proto_notify_error "$interface" PIN_NOT_SPECIFIED
> >   					proto_block_restart "$interface"
> > +					lock -u "$lockname"
> >   					return 1
> >   				fi
> >   				;;
> > @@ -136,6 +160,7 @@ proto_qmi_setup() {
> >   				echo "PIN status failed ($pin1_status)"
> >   				proto_notify_error "$interface" PIN_STATUS_FAILED
> >   				proto_block_restart "$interface"
> > +				lock -u "$lockname"
> >   				return 1
> >   			;;
> >   		esac
> > @@ -156,6 +181,7 @@ proto_qmi_setup() {
> >   			echo "Unable to set PLMN"
> >   			proto_notify_error "$interface" PLMN_FAILED
> >   			proto_block_restart "$interface"
> > +			lock -u "$lockname"
> >   			return 1
> >   		}
> >   	}
> > @@ -172,6 +198,7 @@ proto_qmi_setup() {
> >   		[ -f /sys/class/net/$ifname/qmi/raw_ip ] || {
> >   			echo "Device only supports raw-ip mode but is missing this required driver attribute: /sys/class/net/$ifname/qmi/raw_ip"
> > +			lock -u "$lockname"
> >   			return 1
> >   		}
> > @@ -184,7 +211,10 @@ proto_qmi_setup() {
> >   	echo "Waiting for network registration"
> >   	local registration_timeout=0
> >   	while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
> > -		[ -e "$device" ] || return 1
> > +		[ -e "$device" ] || {
> > +			lock -u "$lockname"
> > +			return 1
> > +		}
> >   		if [ "$registration_timeout" -lt "$timeout" ]; then
> >   			let registration_timeout++
> >   			sleep 1;
> > @@ -192,6 +222,7 @@ proto_qmi_setup() {
> >   			echo "Network registration failed"
> >   			proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED
> >   			proto_block_restart "$interface"
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> >   	done
> > @@ -215,6 +246,7 @@ proto_qmi_setup() {
> >   		if ! [ "$cid_4" -eq "$cid_4" ] 2> /dev/null; then
> >   			echo "Unable to obtain client ID"
> >   			proto_notify_error "$interface" NO_CID
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> > @@ -234,6 +266,7 @@ proto_qmi_setup() {
> >   			echo "Unable to connect IPv4"
> >   			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
> >   			proto_notify_error "$interface" CALL_FAILED
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> > @@ -243,6 +276,7 @@ proto_qmi_setup() {
> >   			echo "No data link!"
> >   			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
> >   			proto_notify_error "$interface" CALL_FAILED
> > +			lock -u "$lockname"
> >   			return 1
> >   		}
> >   	}
> > @@ -252,6 +286,7 @@ proto_qmi_setup() {
> >   		if ! [ "$cid_6" -eq "$cid_6" ] 2> /dev/null; then
> >   			echo "Unable to obtain client ID"
> >   			proto_notify_error "$interface" NO_CID
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> > @@ -271,6 +306,7 @@ proto_qmi_setup() {
> >   			echo "Unable to connect IPv6"
> >   			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
> >   			proto_notify_error "$interface" CALL_FAILED
> > +			lock -u "$lockname"
> >   			return 1
> >   		fi
> > @@ -280,6 +316,7 @@ proto_qmi_setup() {
> >   			echo "No data link!"
> >   			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
> >   			proto_notify_error "$interface" CALL_FAILED
> > +			lock -u "$lockname"
> >   			return 1
> >   		}
> >   	}
> > @@ -343,6 +380,7 @@ proto_qmi_setup() {
> >   		json_close_object
> >   		ubus call network add_dynamic "$(json_dump)"
> >   	}
> > +	lock -u "$lockname"
> >   }
> >   qmi_wds_stop() {
> > @@ -367,10 +405,12 @@ qmi_wds_stop() {
> >   proto_qmi_teardown() {
> >   	local interface="$1"
> > -	local device cid_4 pdh_4 cid_6 pdh_6
> > +	local device localname cid_4 pdh_4 cid_6 pdh_6
> >   	json_get_vars device
> >   	[ -n "$ctl_device" ] && device=$ctl_device
> > +	lockname="/var/lock/LCK..$(basename "$device")"
> > +	lock "$lockname"
> >   	echo "Stopping network $interface"
> > @@ -383,6 +423,8 @@ proto_qmi_teardown() {
> >   	proto_init_update "*" 0
> >   	proto_send_update "$interface"
> > +
> > +	lock -u "$lockname"
> >   }
> >   [ -n "$INCLUDE_ONLY" ] || {
> > 
>
Bjørn Mork Nov. 5, 2018, 5:09 p.m. UTC | #3
Piotr Dymacz <pepe2k@gmail.com> writes:
> On 05.11.2018 00:46, Daniel Golle wrote:
>> Introduce 'imsi' configuration option for proto 'qmi' network
>> interfaces. Setting it makes sure the configuration only gets used
>> on the intended SIM card. In this way, one can have many configurations
>> for different SIM cards selected automatically when the card was either
>> swapped physically or in software (as possible on the APU3 board).
>> In order to allow multiple configurations using the same character
>> device, add locking in netifd protocol handler to avoid overlapping
>> execution of uqmi of the same device.
>
> As the general idea seems correct, I find it very limited and maybe
> problematic (is IMSI number always available before SIM is
> unlocked?). Personally, I would prefer to introduce a
> generic/universal solution, not limited to any of the wwan protocols.

I agree.

But you are right that ICCID is a much better SIM identificator. The
IMSI isn't available until after PIN unlocking.  And the PIN code is
definitely one of the variables you might want to select by SIM... Using
IMSI makes this impossible.

Tested a few modems to see how they present the SIM state:


1) Huawei E3372h-153 (Telia branded), MBIM mode:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n caps
  devicetype: 0002 - removable
  cellularclass: 0001
  voiceclass: 0001 - no-voice
  simclass: 0002
  dataclass: 8000003F
  smscaps: 0003
  controlcaps: 0001
  maxsessions: 0003
  deviceid: 86875702101xxxx
  firmwareinfo: 22.200.05.00.07
  hardwareinfo: CL2E3372HM


a) No SIM inserted (someone should fix the umbim error handling
  here...):

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -t 4 -n subscriber
message not long enough


b) Valid SIM, PIN1 locked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0006 - device-locked
  simiccid: 8947030512101100xxxx
  subscriberid: (null)


c) Unlocked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0001 - initialized
  simiccid: 8947030512101100xxxx
  subscriberid: 24201305013xxxx



2) Huawei E392u-12, QMI:

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-capabilities
{
        "max_tx_channel_rate": 50000000,
        "max_rx_channel_rate": 100000000,
        "data_service": "simultaneous_cs_ps",
        "sim": "supported",
        "networks": [
                "gsm",
                "umts",
                "lte"
        ]
}


a) No SIM inserted:

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-imsi 
"UIM uninitialized"
bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-iccid 
"Invalid arguments given"


b) Valid SIM, PIN1 locked:

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-imsi
"UIM uninitialized"
bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-iccid
"8947030111021700xxxx"

c) Unlocked:

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-imsi
"24201301000xxxx"
bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-iccid
"8947030111021700xxxx"


3) D-Link DWM-156 A7 (Mediatek MTK2), MBIM mode


bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n caps
  devicetype: 0002 - removable
  cellularclass: 0001
  voiceclass: 0003 - simultaneous-voice-data
  simclass: 0002
  dataclass: 001F
  smscaps: 0003
  controlcaps: 0001
  maxsessions: 0002
  deviceid: 35561905015xxxx
  firmwareinfo: MOLY.WR8.W1231.DC.WG.MP.V3
  hardwareinfo: MTK2


a) No SIM inserted:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0002 - sim-not-inserted
  simiccid: (null)
  subscriberid: (null)


b) Valid SIM, PIN1 locked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0006 - device-locked
  simiccid: 8947030111021700xxxx
  subscriberid: (null)


c) Unlocked (cheated while unlocking, as this modem didn't play well with umbim):

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0001 - initialized
  simiccid: 8947030111021700xxxx
  subscriberid: 24201301000xxxx



4) Huawei E367u-2, MBIM mode:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n caps
  devicetype: 0002 - removable
  cellularclass: 0001
  voiceclass: 0001 - no-voice
  simclass: 0002
  dataclass: 8000001F
  smscaps: 0003
  controlcaps: 0001
  maxsessions: 0001
  deviceid: 35361304880xxxx
  firmwareinfo: 11.810.09.00.00
  hardwareinfo: CP1E367UM


a) No SIM inserted:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
message not long enough


b) Valid SIM, PIN1 locked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0006 - device-locked
  simiccid: 9874301011207100xxxx
  subscriberid: (null)

c) Unlocked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm1 -n -t 4 subscriber
  readystate: 0001 - initialized
  simiccid: 9874301011207100xxxx
  subscriberid: 24201301000xxxx


5) Sierra Wireless EM7565, QMI mode

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-capabilities 
{
        "max_tx_channel_rate": 50000000,
        "max_rx_channel_rate": 100000000,
        "data_service": "non_simultaneous_cs_ps",
        "sim": "supported",
        "networks": [
                "umts",
                "lte"
        ]
}

a) Has no support for UIM messages via DMS:

bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-imsi 2>/dev/null
"Not supported"
bjorn@miraculix:~$ uqmi -d /dev/cdc-wdm1  --get-iccid 2>/dev/null
"Not supported"


6) Sierra Wireless EM7455, MBIM mode

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm0 -n caps
  devicetype: 0003 - remote
  cellularclass: 0001
  voiceclass: 0001 - no-voice
  simclass: 0002
  dataclass: 003C
  smscaps: 0003
  controlcaps: 0001
  maxsessions: 0008
  deviceid: 01458200078xxxx
  firmwareinfo: SWI9X30C_02.24.05.06
  hardwareinfo: EM7455


a) No SIM inserted:

Didn't test - too much hassle removing the SIM from my laptop ;-)

b) Valid SIM, PIN1 locked:


bjorn@miraculix:~$ umbim -d /dev/cdc-wdm0 -n -t 4 subscriber
  readystate: 0006 - device-locked
  simiccid: 8947030512101100xxxx
  subscriberid: (null)


c) Unlocked:

bjorn@miraculix:~$ umbim -d /dev/cdc-wdm0 -n -t 4 subscriber
  readystate: 0001 - initialized
  simiccid: 8947030512101100xxxx
  subscriberid: 24201305013xxxx


> I've been using for years slightly different approach which, in the
> same or modified version, might suit better than your idea, also in
> multi-SIM and/or multi-modem solutions or for users often changing SIM
> cards in a single device. Let me try to explain the idea below.
>
> Instead of keeping SIM/operator related configuration (apn,
> pincode...) within the modem network configuration section (glued to a
> specific interface), we introduce a generic 'sim' config file
> (/etc/config/sim), as part of the wwan package, which by default
> contains only one, default configuration (no pin, no auth, generic
> apn, lets say: 'internet'). If the user wants to setup additional
> _SIM-specific_ configuration, section should be named with the SIM
> ICCID number, for example:
>
> config sim
>   option apn 'internet'
>
> ...
>
> config sim '1234567890ABCDEFGHI'
>   option apn 'internet6'
>   option pincode '0000'
>   option auth 'PAP'
>   option username 'user'
>   option password 'pass'
>
> ...

Moving the existing apn and auth parts from 'interface' config to new
'sim' sections will complicate stuff.  Auto-converting the configs can
only solve part of the problem. Outdated docs is worse. And I don't see
a big upside here. Am I missing something?

AFIACS, you can define an 'interface' for each of your SIMs, and achieve
the same as separate 'sim' sections would do.

> SIM ICCID is known to the user (operators print it on the SIM itself)
> and available for the software in advance, even before pin-unlocking.

Yes

> Essentially, this idea maps whole or almost whole configuration
> required for Internet access to SIM, instead of the modem (or, device
> interface in system). During interface setup/bring-up, SIM
> configuration is searched for a specific section (based on the ICCID
> of the SIM in use) and in case it's missing, default one is used.

I believe you can do the same with multiple 'interface' sections,
where only the ones with a matching 'iccid' are activated?

> Of course, this approach requires all available wwan protocols to
> support fetching ICCID from the SIM and also inform the user about
> missing SIM-specific configuration if it's required (SIM requires PIN
> but SIM-specific configuration is missing).
> Plus, some kind of migration mechanism would be required for current
> solution (SIM configuration in network config file).


A common set of settings for all/most types of 3G/LTE modems would be
nice.  But support for the remaining protocols can be added later, can't
it?

I think Daniel's patch looks like a fine start, assuming s/IMSI/ICCID/,
which doesn't prevent further work towards unified LTE modem
configuration. 




Bjørn
diff mbox series

Patch

diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile
index b2f3474400..8eaf0bff3f 100644
--- a/package/network/utils/uqmi/Makefile
+++ b/package/network/utils/uqmi/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uqmi
-PKG_RELEASE:=5
+PKG_RELEASE:=6
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git
diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
index 9b2f69f009..2edbe7c28e 100755
--- a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
+++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
@@ -10,6 +10,7 @@  proto_qmi_init_config() {
 	available=1
 	no_device=1
 	proto_config_add_string "device:device"
+	proto_config_add_string imsi
 	proto_config_add_string apn
 	proto_config_add_string auth
 	proto_config_add_string username
@@ -28,12 +29,12 @@  proto_qmi_init_config() {
 
 proto_qmi_setup() {
 	local interface="$1"
-	local dataformat connstat
-	local device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn timeout $PROTO_DEFAULT_OPTIONS
+	local dataformat connstat imsi_actual
+	local device imsi apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn timeout $PROTO_DEFAULT_OPTIONS
 	local ip4table ip6table
 	local cid_4 pdh_4 cid_6 pdh_6
 	local ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
-	json_get_vars device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn ip4table ip6table timeout $PROTO_DEFAULT_OPTIONS
+	json_get_vars device imsi apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn ip4table ip6table timeout $PROTO_DEFAULT_OPTIONS
 
 	[ "$timeout" = "" ] && timeout="10"
 
@@ -68,10 +69,16 @@  proto_qmi_setup() {
 		return 1
 	}
 
+	lockname="/var/lock/LCK..$devname"
+	lock "$lockname"
+
 	echo "Waiting for SIM initialization"
 	local uninitialized_timeout=0
 	while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
-		[ -e "$device" ] || return 1
+		[ -e "$device" ] || {
+			lock -u "$lockname"
+			return 1
+		}
 		if [ "$uninitialized_timeout" -lt "$timeout" ]; then
 			let uninitialized_timeout++
 			sleep 1;
@@ -79,16 +86,29 @@  proto_qmi_setup() {
 			echo "SIM not initialized"
 			proto_notify_error "$interface" SIM_NOT_INITIALIZED
 			proto_block_restart "$interface"
+			lock -u "$lockname"
 			return 1
 		fi
 	done
 
+	[ -n "$imsi" ] && {
+		imsi_actual="$(uqmi -s -d "$device" --get-imsi | cut -d'"' -f2)"
+		[ "$imsi" = "$imsi_actual" ] || {
+			echo "Configured IMSI doesn't match SIM card."
+			proto_notify_error "$interface" SIM_WRONG
+			proto_set_available "$interface" 0
+			lock -u "$lockname"
+			return 1
+		}
+	}
+
 	if uqmi -s -d "$device" --get-pin-status | grep '"Not supported"' > /dev/null; then
 		[ -n "$pincode" ] && {
 			uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null || {
 				echo "Unable to verify PIN"
 				proto_notify_error "$interface" PIN_FAILED
 				proto_block_restart "$interface"
+				lock -u "$lockname"
 				return 1
 			}
 		}
@@ -106,6 +126,7 @@  proto_qmi_setup() {
 				echo "SIM locked PUK required"
 				proto_notify_error "$interface" PUK_NEEDED
 				proto_block_restart "$interface"
+				lock -u "$lockname"
 				return 1
 				;;
 			not_verified)
@@ -113,6 +134,7 @@  proto_qmi_setup() {
 					echo "PIN verify count value is $pin1_verify_tries this is below the limit of 3"
 					proto_notify_error "$interface" PIN_TRIES_BELOW_LIMIT
 					proto_block_restart "$interface"
+					lock -u "$lockname"
 					return 1
 				}
 				if [ -n "$pincode" ]; then
@@ -120,12 +142,14 @@  proto_qmi_setup() {
 						echo "Unable to verify PIN"
 						proto_notify_error "$interface" PIN_FAILED
 						proto_block_restart "$interface"
+						lock -u "$lockname"
 						return 1
 					}
 				else
 					echo "PIN not specified but required"
 					proto_notify_error "$interface" PIN_NOT_SPECIFIED
 					proto_block_restart "$interface"
+					lock -u "$lockname"
 					return 1
 				fi
 				;;
@@ -136,6 +160,7 @@  proto_qmi_setup() {
 				echo "PIN status failed ($pin1_status)"
 				proto_notify_error "$interface" PIN_STATUS_FAILED
 				proto_block_restart "$interface"
+				lock -u "$lockname"
 				return 1
 			;;
 		esac
@@ -156,6 +181,7 @@  proto_qmi_setup() {
 			echo "Unable to set PLMN"
 			proto_notify_error "$interface" PLMN_FAILED
 			proto_block_restart "$interface"
+			lock -u "$lockname"
 			return 1
 		}
 	}
@@ -172,6 +198,7 @@  proto_qmi_setup() {
 
 		[ -f /sys/class/net/$ifname/qmi/raw_ip ] || {
 			echo "Device only supports raw-ip mode but is missing this required driver attribute: /sys/class/net/$ifname/qmi/raw_ip"
+			lock -u "$lockname"
 			return 1
 		}
 
@@ -184,7 +211,10 @@  proto_qmi_setup() {
 	echo "Waiting for network registration"
 	local registration_timeout=0
 	while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
-		[ -e "$device" ] || return 1
+		[ -e "$device" ] || {
+			lock -u "$lockname"
+			return 1
+		}
 		if [ "$registration_timeout" -lt "$timeout" ]; then
 			let registration_timeout++
 			sleep 1;
@@ -192,6 +222,7 @@  proto_qmi_setup() {
 			echo "Network registration failed"
 			proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED
 			proto_block_restart "$interface"
+			lock -u "$lockname"
 			return 1
 		fi
 	done
@@ -215,6 +246,7 @@  proto_qmi_setup() {
 		if ! [ "$cid_4" -eq "$cid_4" ] 2> /dev/null; then
 			echo "Unable to obtain client ID"
 			proto_notify_error "$interface" NO_CID
+			lock -u "$lockname"
 			return 1
 		fi
 
@@ -234,6 +266,7 @@  proto_qmi_setup() {
 			echo "Unable to connect IPv4"
 			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
 			proto_notify_error "$interface" CALL_FAILED
+			lock -u "$lockname"
 			return 1
 		fi
 
@@ -243,6 +276,7 @@  proto_qmi_setup() {
 			echo "No data link!"
 			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
 			proto_notify_error "$interface" CALL_FAILED
+			lock -u "$lockname"
 			return 1
 		}
 	}
@@ -252,6 +286,7 @@  proto_qmi_setup() {
 		if ! [ "$cid_6" -eq "$cid_6" ] 2> /dev/null; then
 			echo "Unable to obtain client ID"
 			proto_notify_error "$interface" NO_CID
+			lock -u "$lockname"
 			return 1
 		fi
 
@@ -271,6 +306,7 @@  proto_qmi_setup() {
 			echo "Unable to connect IPv6"
 			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
 			proto_notify_error "$interface" CALL_FAILED
+			lock -u "$lockname"
 			return 1
 		fi
 
@@ -280,6 +316,7 @@  proto_qmi_setup() {
 			echo "No data link!"
 			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
 			proto_notify_error "$interface" CALL_FAILED
+			lock -u "$lockname"
 			return 1
 		}
 	}
@@ -343,6 +380,7 @@  proto_qmi_setup() {
 		json_close_object
 		ubus call network add_dynamic "$(json_dump)"
 	}
+	lock -u "$lockname"
 }
 
 qmi_wds_stop() {
@@ -367,10 +405,12 @@  qmi_wds_stop() {
 proto_qmi_teardown() {
 	local interface="$1"
 
-	local device cid_4 pdh_4 cid_6 pdh_6
+	local device localname cid_4 pdh_4 cid_6 pdh_6
 	json_get_vars device
 
 	[ -n "$ctl_device" ] && device=$ctl_device
+	lockname="/var/lock/LCK..$(basename "$device")"
+	lock "$lockname"
 
 	echo "Stopping network $interface"
 
@@ -383,6 +423,8 @@  proto_qmi_teardown() {
 
 	proto_init_update "*" 0
 	proto_send_update "$interface"
+
+	lock -u "$lockname"
 }
 
 [ -n "$INCLUDE_ONLY" ] || {