dexter has abandoned this change. ( https://gerrit.osmocom.org/c/osmo-mgw/+/34404?usp=email )
Change subject: mgcp_client_fsm: allocate struct mgcp_conn_peer dynamically
......................................................................
Abandoned
As far as I remember (by the comments) the context was that we wanted to allocate mgcp_conn_peer dynamically to lower the risk with ABI/memory size problems in the future. However, the price would have been to make an incompatible API change now. Given that the patch is very old and we apparently have no problems with, let's abandon it.
--
To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/34404?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: abandon
Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-Change-Id: I523d0fcb020f7d46323c497a4be9ee00d5f242ba
Gerrit-Change-Number: 34404
Gerrit-PatchSet: 16
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/onomondo-eim/+/42991?usp=email )
Change subject: mnesia_db_rest: add comment on why we create an euicc entry early
......................................................................
mnesia_db_rest: add comment on why we create an euicc entry early
Even though it is technically not necessary, we ensure that an
entry is present in the euicc table on each REST API call. Let's
add a comment to explain why we do it anyway.
Change-Id: Ifb9340655c5f36e074a1a92c0e234ef62c79b9d8
---
M src/mnesia_db_rest.erl
1 file changed, 6 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/91/42991/1
diff --git a/src/mnesia_db_rest.erl b/src/mnesia_db_rest.erl
index 41b4a0c..0976beb 100644
--- a/src/mnesia_db_rest.erl
+++ b/src/mnesia_db_rest.erl
@@ -41,7 +41,13 @@
% Create REST resource (order)
create(Facility, EidValue, Order) ->
+ % Ensure that an euicc entry is present in the database for the given EidValue. In case no entry exists yet, a new
+ % entry is created with default parameters from sys.config, which is is sufficient in many usecases. From the
+ % technical perspective, this is just a convenience feature, which frees the REST API user from having to create an
+ % euicc entry manually before performming the first operation.
ok = mnesia_db_euicc:create_if_not_exist(EidValue),
+
+ % Continue with the normal creation of the REST resource.
ResourceId = uuid:uuid_to_string(uuid:get_v4_urandom()),
Timestamp = os:system_time(seconds),
Row = #rest{
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42991?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: Ifb9340655c5f36e074a1a92c0e234ef62c79b9d8
Gerrit-Change-Number: 42991
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/onomondo-eim/+/42994?usp=email )
Change subject: doc/build.md: fix typo
......................................................................
doc/build.md: fix typo
Related: SYS#8100
Change-Id: Ie6a066f3289fbdde40f55bd9f38a3dd90102e7e6
---
M doc/build.md
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/94/42994/1
diff --git a/doc/build.md b/doc/build.md
index 5bb08af..660791b 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -252,7 +252,7 @@
Onomondo-eim supports the simultaneous usage of IoT eUICCs and consumer eUICCs. The type of the eUICC must be set for
each eUICC via the REST API once, if it differs from the default set with the configuration option `consumer_euicc`.
-For larger installations, where both flavours of eUICCs are used, it is recommended to run two dedicated eIM
+For larger installations, where both flavors of eUICCs are used, it is recommended to run two dedicated eIM
instances, one for each eUICC flavor.
### vm.args
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42994?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: Ie6a066f3289fbdde40f55bd9f38a3dd90102e7e6
Gerrit-Change-Number: 42994
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/onomondo-eim/+/42992?usp=email )
Change subject: contrib/tryme_euiccDataRequest: fixup example tag string
......................................................................
contrib/tryme_euiccDataRequest: fixup example tag string
The eUICC data request takes a string with TLV tags as input. The
example in this example still uses tags from SGP.32 V.1.0.1, let's
update the string so that it is compliant with SGP.32 V.1.2.
(see also SGP.32, section 2.11.1.2)
Related: SYS:8100
Change-Id: I5be04c954330638d3e7d78e8f5f280bebb707efa
---
M contrib/tryme_euiccDataRequest.sh
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/92/42992/1
diff --git a/contrib/tryme_euiccDataRequest.sh b/contrib/tryme_euiccDataRequest.sh
index 7411c13..ba70a69 100755
--- a/contrib/tryme_euiccDataRequest.sh
+++ b/contrib/tryme_euiccDataRequest.sh
@@ -1,6 +1,6 @@
#!/bin/bash
. ./tryme.cfg
-JSON='{ "eidValue" : "'$EID'", "order" : { "edr" : {"tagList" : "80BF20BF228384A5A688A9BF2B" } } }'
+JSON='{ "eidValue" : "'$EID'", "order" : { "edr" : { "tagList" : "81BF20BF228384A5A6A8A9A0" } } }'
RC=`./restop.py -c -f edr -j "$JSON"`
echo $RC
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42992?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: I5be04c954330638d3e7d78e8f5f280bebb707efa
Gerrit-Change-Number: 42992
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/onomondo-eim/+/42993?usp=email )
Change subject: mnesia_db_euicc: renovate handling of euicc table (mnesia, REST)
......................................................................
mnesia_db_euicc: renovate handling of euicc table (mnesia, REST)
The REST API that allows users to set certain eUICC parameters
(we call them "states" from now on) only allows to set eUICC
states, but doesn't allow to read them back.
With this patch, we renovate the handling of the mnesia euicc
table from the ground up so that REST API users have read and
write access to the states stored in the mnesia euicc table.
Related: SYS#8100
The original purpose of the euicc table was to hold static params
for an eUICC (e.g. the public key or the flag that tells if it is
a consumer eUICC or not). Now that we plan to extend the scope
of the euicc table, it makes more sense to talk about states rather
than parameters.
Change-Id: I74c602555b194a28d6eb9dd67ec4c6a8865fcb77
---
M contrib/rest_api_resource_schema.json
M contrib/rest_api_response_schema.json
A contrib/tryme_euicc_get_state.sh
A contrib/tryme_euicc_set_state.sh
D contrib/tryme_set_euicc_param.sh
M doc/database.md
M doc/examples.md
M doc/rest_api.md
M src/crypto_utils.erl
M src/esipa_asn1_handler_utils.erl
M src/mnesia_db.erl
M src/mnesia_db_euicc.erl
12 files changed, 292 insertions(+), 173 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/93/42993/1
diff --git a/contrib/rest_api_resource_schema.json b/contrib/rest_api_resource_schema.json
index ce1ae7d..6519dfa 100644
--- a/contrib/rest_api_resource_schema.json
+++ b/contrib/rest_api_resource_schema.json
@@ -286,33 +286,47 @@
},
{
"euicc": {
- "description": "set a parameter in the euicc master data table",
- "type": "array",
- "items": {
- "counterValue": {
- "description": "sets the signature counter to a specified value (use with caution)",
- "type": "integer"
+ "description": "order to perform an operation on eUICC states stored in the euicc table (mnesia)",
+ "type": "object",
+ "properties": {
+ "set": {
+ "description": "values of eUICC states to set",
+ "type": "array",
+ "items": {
+ "counterValue": {
+ "description": "signature counter to a specified value (use with caution)",
+ "type": "integer"
+ },
+ "consumerEuicc": {
+ "description": "tells the eIM that the remote end (IPAd) uses a consumer eUICC with an IoT eUICC emulation mode",
+ "type": "boolean"
+ },
+ "associationToken": {
+ "description": "association token that the eUICC uses to identify this eIM internally",
+ "type": "integer"
+ },
+ "signPubKey": {
+ "description": "public key to be used for checking eUICC package results",
+ "type": "string",
+ "pattern": "^[0-9,A-F]{2,32}$"
+ },
+ "signAlgo": {
+ "description": "algorithm to be used for checking eUICC package results",
+ "type": "string",
+ "enum": [
+ "prime256v1",
+ "brainpoolP256r1"
+ ]
+ }
+ }
},
- "consumerEuicc": {
- "description": "tells the eIM that the remote end (IPAd) uses a consumer eUICC with an IoT eUICC emulation mode",
- "type": "boolean"
- },
- "associationToken": {
- "description": "association token that the eUICC uses to identify this eIM internally",
- "type": "integer"
- },
- "signAlgo": {
- "description": "algorithm to be used for checking eUICC package results",
- "type": "string",
- "enum": [
- "prime256v1",
- "brainpoolP256r1"
- ]
- },
- "signPubKey": {
- "description": "public key to be used for checking eUICC package results",
- "type": "string",
- "pattern": "^[0-9,A-F]{2,32}$"
+ "get": {
+ "description": "names of the eUICC states to retrieve",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": ["counterValue", "consumerEuicc", "associationToken", "signAlgo", "signPubKey"]
+ }
}
}
}
diff --git a/contrib/rest_api_response_schema.json b/contrib/rest_api_response_schema.json
index 7ec2735..f2a5165 100644
--- a/contrib/rest_api_response_schema.json
+++ b/contrib/rest_api_response_schema.json
@@ -413,14 +413,36 @@
}
},
{
- "euiccUpdateResult": {
- "description": "contains the result of a parameter update in the euicc master data table",
- "type": "string",
- "enum": [
- "ok",
- "badParamFormat",
- "badParam"
- ]
+ "euiccStateResult": {
+ "description": "contains the result of an eUICC state set/get operation",
+ "type": "array",
+ "items": {
+ "counterValue": {
+ "description": "signature counter to a specified value (use with caution)",
+ "type": "integer"
+ },
+ "consumerEuicc": {
+ "description": "tells the eIM that the remote end (IPAd) uses a consumer eUICC with an IoT eUICC emulation mode",
+ "type": "boolean"
+ },
+ "associationToken": {
+ "description": "association token that the eUICC uses to identify this eIM internally",
+ "type": "integer"
+ },
+ "signPubKey": {
+ "description": "public key to be used for checking eUICC package results",
+ "type": "string",
+ "pattern": "^[0-9,A-F]{2,32}$"
+ },
+ "signAlgo": {
+ "description": "algorithm to be used for checking eUICC package results",
+ "type": "string",
+ "enum": [
+ "prime256v1",
+ "brainpoolP256r1"
+ ]
+ }
+ }
}
},
{
@@ -514,6 +536,7 @@
"badPsmo",
"badEco",
"badEdr",
+ "badState",
"badOrder",
"abortedOrder",
"stuckOrder",
diff --git a/contrib/tryme_euicc_get_state.sh b/contrib/tryme_euicc_get_state.sh
new file mode 100755
index 0000000..524d37d
--- /dev/null
+++ b/contrib/tryme_euicc_get_state.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+. ./tryme.cfg
+
+# States we want to retrieve with this request.
+STATES='"counterValue", "consumerEuicc", "signAlgo", "signPubKey"'
+
+JSON='{ "eidValue" : "'$EID'", "order" : { "euicc" : { "get" : [ '$STATES' ] } } }'
+RC=`./restop.py -c -f euicc -j "$JSON"`
+echo $RC
+
+echo "---------------------------------------8<---------------------------------------"
+RESOURCE_ID=`echo $RC | cut -d '/' -f 6`
+echo "ResourceId =" $RESOURCE_ID
+./tryme_lookup.sh euicc $RESOURCE_ID
diff --git a/contrib/tryme_euicc_set_state.sh b/contrib/tryme_euicc_set_state.sh
new file mode 100755
index 0000000..1ca8b9f
--- /dev/null
+++ b/contrib/tryme_euicc_set_state.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+. ./tryme.cfg
+
+# States we want to set with this request (list does not have to be complete, states not listest here are left
+# unchanged.
+STATES='{ "counterValue" : 1000 }, { "consumerEuicc" : false }, { "signAlgo" : "prime256v1" }, { "signPubKey" : "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB" }'
+
+JSON='{ "eidValue" : "'$EID'", "order" : { "euicc" : { "set" : [ '$STATES' ] } } }'
+RC=`./restop.py -c -f euicc -j "$JSON"`
+echo $RC
+
+echo "---------------------------------------8<---------------------------------------"
+RESOURCE_ID=`echo $RC | cut -d '/' -f 6`
+echo "ResourceId =" $RESOURCE_ID
+./tryme_lookup.sh euicc $RESOURCE_ID
diff --git a/contrib/tryme_set_euicc_param.sh b/contrib/tryme_set_euicc_param.sh
deleted file mode 100755
index 32c9ec9..0000000
--- a/contrib/tryme_set_euicc_param.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-. ./tryme.cfg
-
-JSON='{ "eidValue" : "'$EID'", "order" : { "euicc": [ { "counterValue" : 1000 }, { "consumerEuicc" : false }, { "signAlgo" : "prime256v1" }, { "signPubKey" : "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB" } ] } }'
-RC=`./restop.py -c -f euicc -j "$JSON"`
-echo $RC
-
-echo "---------------------------------------8<---------------------------------------"
-RESOURCE_ID=`echo $RC | cut -d '/' -f 6`
-echo "ResourceId =" $RESOURCE_ID
-./tryme_lookup.sh euicc $RESOURCE_ID
diff --git a/doc/database.md b/doc/database.md
index 00c377e..8ae5471 100644
--- a/doc/database.md
+++ b/doc/database.md
@@ -88,10 +88,13 @@
### `euicc` Table
-The `euicc` table contains the eUICC master data. This is in particular the EID and other meta information that is
-required for the eIM to operate. The data in this table is usually automatically collected and updated by the eIM.
-However, there may be situations where the REST API user wants to update certain parameters of the `euicc` table.
-This is why the REST API allows to modify the contents of the `euicc` table via `orders` from the `euicc` `facility`
+The `euicc` table contains the eUICC state data for each eUICC. eUICC states are any type of information that is
+related to a specific eUICC (EID). A prominet example would be the `counterValue`, which is used for replay protection,
+but also the `signPubKey` is considered as an eUICC state, even though it remains constant.
+
+The states stored in this table are usually automatically collected and updated by the eIM. However, the REST API user
+may retrieve (get) or update (set) any of the states at any time if needed. eUICC states are managed using `orders`
+from the `euicc` `facility`
The `euicc` table maintains the following columns:
diff --git a/doc/examples.md b/doc/examples.md
index 889681d..9f3726a 100644
--- a/doc/examples.md
+++ b/doc/examples.md
@@ -123,7 +123,7 @@
information back. The returned data fields are in their ASN.1 encoded representation unless the requested tag consists
of a single primitive type (e.g. `associationToken`).
-### Setting a Parameters in the `euicc` Table
+### Setting States in the `euicc` Table
Even though the `euicc` table is populated automatically, it may still be that the REST API user wants to adjust
certain parameters. Let's assume that we have a setup that mostly uses consumer eUICCs in an IoT emulation mode. Now we
@@ -133,21 +133,43 @@
In this case we would craft an order like this:
```
-{ "eidValue" : "'$EID'", "order" : { "euicc": [ { "counterValue" : 1000 }, { "consumerEuicc" : false }, { "signAlgo" : "prime256v1" }, { "signPubKey" : "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB" } ] } }'
+{ "eidValue" : "'$EID'", "order" : { "euicc" : { "set" : [ { "counterValue" : 1000 }, { "consumerEuicc" : false }, { "signAlgo" : "prime256v1" }, { "signPubKey" : "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB" } ] } } }
```
We would edit the order into tryme_set_euicc_param.sh and run the script:
```
-./tryme_set_euicc_param.sh X 12345678900000000000000000001234
+./tryme_euicc_set_state.sh X 12345678900000000000000000001234
```
The order will execute as an internal process. This means that no IPAd interaction is involved. However, on the REST
-API the behavior will not be any different, except that the `status` will change from `new` to `done` directly. When
-all changes to the `euicc` table are made accordingly, we should get a result like this:
+API the behavior will not be any different. When all changes to the `euicc` table are made accordingly the eIM will
+echo the state values in the result:
```
-{"status": "done", "timestamp": "1721309044", "resource": {"eidValue": "12345678900000000000000000001234", "order": {"euicc": [{"counterValue": 1000}, {"consumerEuicc": false}, {"signAlgo": "prime256v1"}, {"signPubKey": "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB"}]}}, "outcome": [{"euiccUpdateResult": "ok"}], "debuginfo": "836400046E6F6E65"}
+{"status": "done", "timestamp": "1783694896", "resource": {"eidValue": "12345678900000000000000000001234", "order": {"euicc": {"set": [{"counterValue": 1000}, {"consumerEuicc": false}, {"signAlgo": "prime256v1"}, {"signPubKey": "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB"}]}}}, "outcome": [{"euiccStateResult": [{"counterValue": 1000}, {"consumerEuicc": false}, {"signAlgo": "prime256v1"}, {"signPubKey": "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB"}]}], "debuginfo": "8377046E6F6E65"}
```
Now the eIM will treat the eUICC as a native IoT eUICC, a proper public key set and the counter value is high enough
so that we can sign new eUICC packages correctly.
+
+### Retrieving a States from the `euicc` Table
+
+eUICC states stored in the `euicc` Table can be retrieved at any time by sending a list with the states we want to
+retrieve to the eIM. The list does not have to be complete. It is possible to limit the focus on a small subset of
+states. The following example shows an order that would retrieve the `counterValue`, the `consumerEuicc` flag, the
+`signAlgo` and the `signPubKey`:
+
+```
+{ "eidValue" : "12345678900000000000000000001234", "order" : { "euicc" : { "get" : [ "counterValue", "consumerEuicc", "signAlgo", "signPubKey" ] } } }
+```
+
+We would edit the order into tryme_set_euicc_param.sh and run the script:
+```
+./tryme_euicc_get_state.sh X 12345678900000000000000000001234
+```
+
+The eIM will respond with a list of key value pairs of the requested eUICC states:
+
+```
+{"status": "done", "timestamp": "1783695656", "resource": {"eidValue": "12345678900000000000000000001234", "order": {"euicc": {"get": ["counterValue", "consumerEuicc", "signAlgo", "signPubKey"]}}}, "outcome": [{"euiccStateResult": [{"counterValue": 1000}, {"consumerEuicc": false}, {"signAlgo": "prime256v1"}, {"signPubKey": "04BD2C55B28B4E801CA0B14F195788FD86C7FF49764C88A2934C69594A26FF647549F3F16060BD9C8D793D95D0126FA429C94966FE7842967263795A73C498F1DB"}]}], "debuginfo": "8377046E6F6E65"}
+```
diff --git a/doc/rest_api.md b/doc/rest_api.md
index d49299e..59af59c 100644
--- a/doc/rest_api.md
+++ b/doc/rest_api.md
@@ -13,7 +13,7 @@
* `psmo`: Profile State Management Operations (PSMO)
* `eco`: Eim Configuration Operations (eCO)
* `edr`: eUICC data request (see also GSMA SGP.32, section 2.11.1.2)
-* `euicc`: eim-local eUICC configuration Operations
+* `euicc`: eim-local eUICC state update (set) or retrieve (get) operations
The purpose of the facilities is to provide separation at URL level. This allows for easier filtering to restrict
access for specific REST API users.
diff --git a/src/crypto_utils.erl b/src/crypto_utils.erl
index 63abc59..21929b5 100644
--- a/src/crypto_utils.erl
+++ b/src/crypto_utils.erl
@@ -40,7 +40,7 @@
sign_euiccPackageSigned(EuiccPackageSigned, EidValue) ->
% Read the AssociationToken
- {ok, AssociationToken} = mnesia_db_euicc:param_get(EidValue, associationToken),
+ {ok, AssociationToken} = mnesia_db_euicc:state_get(EidValue, associationToken),
%Format message to be signed
{ok, EuiccPackageSignedEnc} = 'SGP32Definitions':encode(
@@ -64,10 +64,10 @@
verify_signature(Message, Signature, EidValue) ->
DERSignature = plain_to_der(Signature),
- {ok, SubjectPublicKeyHex} = mnesia_db_euicc:param_get(EidValue, signPubKey),
+ {ok, SubjectPublicKeyHex} = mnesia_db_euicc:state_get(EidValue, signPubKey),
SubjectPublicKey = utils:hex_to_binary(SubjectPublicKeyHex),
- {ok, SignAlgo} = mnesia_db_euicc:param_get(EidValue, signAlgo),
+ {ok, SignAlgo} = mnesia_db_euicc:state_get(EidValue, signAlgo),
NamedCurve =
case SignAlgo of
<<"prime256v1">> ->
@@ -108,11 +108,11 @@
end.
verify_euiccPackageResultSigned(EuiccPackageResult, EidValue) ->
- {ok, ConsumerEuicc} = mnesia_db_euicc:param_get(EidValue, consumerEuicc),
+ {ok, ConsumerEuicc} = mnesia_db_euicc:state_get(EidValue, consumerEuicc),
case ConsumerEuicc of
false ->
% Read the AssociationToken
- {ok, AssociationToken} = mnesia_db_euicc:param_get(EidValue, associationToken),
+ {ok, AssociationToken} = mnesia_db_euicc:state_get(EidValue, associationToken),
case EuiccPackageResult of
{euiccPackageResultSigned, EuiccPackageResultSigned} ->
@@ -275,15 +275,15 @@
_ ->
<<"unknown">>
end,
- ok = mnesia_db_euicc:param_set(EidValue, signPubKey, utils:binary_to_hex(SignPubKey)),
- ok = mnesia_db_euicc:param_set(EidValue, signAlgo, SignAlgo),
+ ok = mnesia_db_euicc:state_set(EidValue, signPubKey, utils:binary_to_hex(SignPubKey)),
+ ok = mnesia_db_euicc:state_set(EidValue, signAlgo, SignAlgo),
ok;
_ ->
error
end.
store_euicc_pubkey_from_authenticateResponseOk(AuthRespOk, EidValue) ->
- case mnesia_db_euicc:param_get(EidValue, signPubKey) of
+ case mnesia_db_euicc:state_get(EidValue, signPubKey) of
{ok, <<>>} ->
% There is no public key stored yet for this eUICC, use the public
% key provided in the eUICC certificate
@@ -296,7 +296,7 @@
end.
store_euicc_pubkey_from_ipaEuiccDataResponse(IpaEuiccDataResponse, EidValue) ->
- case mnesia_db_euicc:param_get(EidValue, signPubKey) of
+ case mnesia_db_euicc:state_get(EidValue, signPubKey) of
{ok, <<>>} ->
% There is no public key stored yet for this eUICC, use the public
% key provided in the eUICC certificate
diff --git a/src/esipa_asn1_handler_utils.erl b/src/esipa_asn1_handler_utils.erl
index 0d77ba7..ead177f 100644
--- a/src/esipa_asn1_handler_utils.erl
+++ b/src/esipa_asn1_handler_utils.erl
@@ -51,7 +51,7 @@
CheckCounterValue = fun(Map) ->
{EidValue, _, _} = mnesia_db_work:pickup(Pid, EimTransactionId),
CounterValueIpad = maps:get(counterValue, Map),
- {ok, CounterValueEim} = mnesia_db_euicc:param_get(EidValue, counterValue),
+ {ok, CounterValueEim} = mnesia_db_euicc:state_get(EidValue, counterValue),
case CounterValueIpad of
CounterValueEim ->
ok;
diff --git a/src/mnesia_db.erl b/src/mnesia_db.erl
index d8e7afa..63028c4 100644
--- a/src/mnesia_db.erl
+++ b/src/mnesia_db.erl
@@ -61,8 +61,8 @@
logger:notice(" work table created\n")
end,
- % The euicc table will store the eUICC master data, such as the eID and the counterValue that is required for
- % the replay protection.
+ % The euicc table will store eUICC states, such as the eID and the counterValue that is required for the replay
+ % protection.
case
mnesia:create_table(
euicc,
diff --git a/src/mnesia_db_euicc.erl b/src/mnesia_db_euicc.erl
index 013b377..9f27ed3 100644
--- a/src/mnesia_db_euicc.erl
+++ b/src/mnesia_db_euicc.erl
@@ -4,13 +4,17 @@
%
% Author: Philipp Maier <pmaier(a)sysmocom.de> / sysmocom - s.f.m.c. GmbH
+% An eUICC procedure in the context of this module has nothing to do with any of the procedures specified in
+% GSMA SGP.22 or SGP.32. In this module an eUICC procedure is a virtual procedure were states in the
+% euicc table are set.
+
-module(mnesia_db_euicc).
-include_lib("stdlib/include/qlc.hrl").
-include("mnesia_db_rest.hrl").
-include("mnesia_db_euicc.hrl").
% euicc functions, to be called by the eIM code (from inside)
--export([counter_tick/1, param_get/2, param_set/3, create_if_not_exist/1]).
+-export([counter_tick/1, state_get/2, state_set/3, create_if_not_exist/1]).
% debugging
-export([dump/0]).
@@ -38,7 +42,7 @@
present
end.
-% Create a new eUICC master data entry
+% Create a new eUICC state data entry
create_if_not_exist(EidValue) ->
Trans = fun() ->
trans_create_if_not_exist(EidValue)
@@ -46,14 +50,16 @@
{atomic, Result} = mnesia:transaction(Trans),
case Result of
ok ->
- logger:info("eUICC: creating new master data entry,~neID=~p~n", [EidValue]),
+ logger:info("eUICC: creating new eUICC state data entry,~neID=~p~n", [EidValue]),
ok;
present ->
ok;
_ ->
- logger:error("eUICC: cannot create master data entry, database error,~neID=~p~n", [
- EidValue
- ]),
+ logger:error(
+ "eUICC: cannot create new eUICC state data entry, database error,~neID=~p~n", [
+ EidValue
+ ]
+ ),
error
end.
@@ -88,8 +94,8 @@
error
end.
-%update one specific parameter in the euicc table
-trans_update_param(EidValue, Name, Value) ->
+trans_state_set(EidValue, Name, Value) ->
+ trans_create_if_not_exist(EidValue),
Q = qlc:q([X || X <- mnesia:table(euicc), X#euicc.eidValue == EidValue]),
Rows = qlc:e(Q),
case Rows of
@@ -106,121 +112,82 @@
signAlgo ->
mnesia:write(Row#euicc{signAlgo = Value});
_ ->
- error
+ throw(badState)
end;
[] ->
- error;
+ throw(eidUnknown);
_ ->
- error
+ throw(undefinedError)
end.
-% Get an eUICC parameter by its name (atom)
-param_get(EidValue, Name) ->
- Trans = fun() ->
- Q = qlc:q([X || X <- mnesia:table(euicc), X#euicc.eidValue == EidValue]),
- Rows = qlc:e(Q),
- case Rows of
- [Row | _] ->
- case Name of
- counterValue ->
- {ok, Row#euicc.counterValue};
- consumerEuicc ->
- {ok, Row#euicc.consumerEuicc};
- associationToken ->
- {ok, Row#euicc.associationToken};
- signPubKey ->
- {ok, Row#euicc.signPubKey};
- signAlgo ->
- {ok, Row#euicc.signAlgo};
- _ ->
- error
- end;
- [] ->
- error;
- _ ->
- error
- end
- end,
+trans_state_get(EidValue, Name) ->
+ Q = qlc:q([X || X <- mnesia:table(euicc), X#euicc.eidValue == EidValue]),
+ Rows = qlc:e(Q),
+ case Rows of
+ [Row | _] ->
+ case Name of
+ counterValue ->
+ Row#euicc.counterValue;
+ consumerEuicc ->
+ Row#euicc.consumerEuicc;
+ associationToken ->
+ Row#euicc.associationToken;
+ signPubKey ->
+ Row#euicc.signPubKey;
+ signAlgo ->
+ Row#euicc.signAlgo;
+ _ ->
+ throw(badState)
+ end;
+ [] ->
+ throw(eidUnknown);
+ _ ->
+ throw(undefinedError)
+ end.
- {atomic, Result} = mnesia:transaction(Trans),
+% Get an eUICC state by its name (atom)
+state_get(EidValue, Name) ->
+ Trans = fun() ->
+ trans_state_get(EidValue, Name)
+ end,
+ Result = mnesia:transaction(Trans),
case Result of
- {ok, Value} ->
- logger:info("eUICC: reading eUICC parameter,~neID=~p, name=~p, value=~p~n", [
+ {atomic, Value} ->
+ logger:info("eUICC: reading eUICC state,~neID=~p, name=~p, value=~p~n", [
EidValue, Name, Value
]),
{ok, Value};
_ ->
- logger:error("eUICC: cannot read eUICC parameter,~neID=~p, name=~p~n", [EidValue, Name]),
+ logger:error("eUICC: cannot read eUICC state,~neID=~p, name=~p~n", [EidValue, Name]),
error
end.
-% Update an eUICC parameter by its name (atom)
-param_set(EidValue, Name, Value) ->
+% Update an eUICC state by its name (atom)
+state_set(EidValue, Name, Value) ->
Trans = fun() ->
- trans_update_param(EidValue, Name, Value)
+ trans_state_set(EidValue, Name, Value)
end,
- {atomic, Result} = mnesia:transaction(Trans),
+ Result = mnesia:transaction(Trans),
case Result of
- ok ->
- logger:info("eUICC: writing eUICC parameter,~neID=~p, name=~p, value=~p~n", [
+ {atomic, ok} ->
+ logger:info("eUICC: writing eUICC state,~neID=~p, name=~p, value=~p~n", [
EidValue, Name, Value
]),
ok;
_ ->
- logger:error("eUICC: cannot write eUICC parameter,~neID=~p, name=~p~n", [EidValue, Name]),
+ logger:error("eUICC: cannot write eUICC state,~neID=~p, name=~p~n", [EidValue, Name]),
error
end.
-% Handle REST requests in regular intervals
-timer_rest() ->
- % An eUICC procedure in the context of this module has nothing to do with any of the procedures specified in
- % GSMA SGP.22 or SGP.32. In this module an eUICC procedure is a virtual procedure were parameters in the
- % euicc table are set.
+timer_rest_fetch() ->
+ % Fetch the rest resources with incoming orders from the rest table and set their status (wihich is initially set
+ % to "new" to "work", so that the REST API user knows that the order has been accepted for processing. Finally, we
+ % will return the fetched rest resources back to the caller, so that he can proceed with the processing of the
+ % orders.
- HandleParam = fun(ResourceId, EidValue, Param) ->
- case Param of
- {[{Name, Value}]} ->
- case trans_update_param(EidValue, binary_to_atom(Name), Value) of
- ok ->
- mnesia_db_rest:trans_set_status(
- ResourceId,
- done,
- [{[{euiccUpdateResult, ok}]}],
- none
- );
- _ ->
- mnesia_db_rest:trans_set_status(
- ResourceId,
- done,
- [{[{euiccUpdateResult, badParam}]}],
- none
- )
- end;
- _ ->
- mnesia_db_rest:trans_set_status(
- ResourceId,
- done,
- [{[{euiccUpdateResult, badParamFormat}]}],
- none
- )
- end
+ SetStatus = fun({ResourceId, _EidValue, _Order}) ->
+ mnesia_db_rest:trans_set_status(ResourceId, work, [], none)
end,
-
- % Parse order and process each parameter individually
- HandleResource = fun({ResourceId, EidValue, Order}) ->
- trans_create_if_not_exist(EidValue),
- case Order of
- {[{<<"euicc">>, ParameterList}]} ->
- [HandleParam(ResourceId, EidValue, Param) || Param <- ParameterList],
- ok;
- _ ->
- mnesia_db_rest:trans_set_status(
- ResourceId, done, [{[{procedureError, badOrder}]}], none
- )
- end
- end,
-
- % Look into facility euicc and find the first entry that is in status "new".
Trans = fun() ->
Q = qlc:q([
{X#rest.resourceId, X#rest.eidValue, X#rest.order}
@@ -229,27 +196,99 @@
Rows = qlc:e(Q),
case Rows of
[] ->
- ok;
+ [];
Rows ->
- [HandleResource(Row) || Row <- Rows],
- ok
+ [SetStatus(Row) || Row <- Rows],
+ Rows
end
end,
- {atomic, Result} = mnesia:transaction(Trans),
+ Result = mnesia:transaction(Trans),
case Result of
- ok ->
- ok;
+ {atomic, Resources} ->
+ {ok, Resources};
_ ->
- logger:error("eUICC: euicc procedure failed, database error~n"),
+ logger:error("eUICC: order fetch failed, database error~n"),
error
+ end.
+
+timer_rest_process(RestResource) ->
+ % Process the order contained in the given REST resource and return the outcome when done.
+
+ HandleStateSet = fun(EidValue, State) ->
+ case State of
+ {[{Name, Value}]} ->
+ ok = trans_state_set(EidValue, binary_to_atom(Name), Value),
+ {[{Name, Value}]};
+ _ ->
+ throw(badOrder)
+ end
end,
+ HandleStateGet = fun(EidValue, Name) ->
+ {[{Name, trans_state_get(EidValue, binary_to_atom(Name))}]}
+ end,
+ Trans = fun() ->
+ {_ResourceId, EidValue, Order} = RestResource,
+ case Order of
+ {[{<<"euicc">>, {[{<<"set">>, States}]}}]} ->
+ [{[{euiccStateResult, [HandleStateSet(EidValue, State) || State <- States]}]}];
+ {[{<<"euicc">>, {[{<<"get">>, States}]}}]} ->
+ [{[{euiccStateResult, [HandleStateGet(EidValue, State) || State <- States]}]}];
+ _ ->
+ throw(badOrder)
+ end
+ end,
+
+ Result = mnesia:transaction(Trans),
+ case Result of
+ {atomic, Outcome} ->
+ Outcome;
+ {aborted, {throw, ErrorCode}} ->
+ logger:error("eUICC: order process failed with error code: ~p~n", [ErrorCode]),
+ [{[{procedureError, ErrorCode}]}];
+ _ ->
+ logger:error("eUICC: order process failed, database error~n"),
+ [{[{procedureError, undefinedError}]}]
+ end.
+
+timer_rest_finish(RestResource, Outcome) ->
+ % Write the given outcome to the given REST resource and set the status to "done" to notify the REST API user that
+ % the order processing has finished.
+
+ Trans = fun() ->
+ {ResourceId, _EidValue, _Order} = RestResource,
+ mnesia_db_rest:trans_set_status(ResourceId, done, Outcome, none)
+ end,
+
+ Result = mnesia:transaction(Trans),
+ case Result of
+ {atomic, ok} ->
+ ok;
+ {aborted, {throw, ErrorCode}} ->
+ logger:error("eUICC: order finish failed with error code: ~p~n", [ErrorCode]),
+ error;
+ _ ->
+ logger:error("eUICC: order finish failed, database error~n"),
+ error
+ end.
+
+% Handle euicc table related REST resources in regular intervals.
+timer_rest() ->
+ % Fetch REST resources with new orders from rest table and mark them as work in progress
+ {ok, RestResources} = timer_rest_fetch(),
+
+ % Process each REST resource individually
+ ProcessRestResource = fun(RestResource) ->
+ Outcome = timer_rest_process(RestResource),
+ timer_rest_finish(RestResource, Outcome)
+ end,
+ [ProcessRestResource(RestResource) || RestResource <- RestResources],
% Next euicc procedure in 10 secs.
{ok, _} = timer:apply_after(10000, mnesia_db_euicc, timer_rest, []),
ok.
-% Dump all eUICCs we are aware of
+% Dump all eUICC states we are aware of
dump() ->
Trans = fun() ->
Q = qlc:q([X || X <- mnesia:table(euicc)]),
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42993?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: I74c602555b194a28d6eb9dd67ec4c6a8865fcb77
Gerrit-Change-Number: 42993
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Attention is currently required from: laforge.
Hello Jenkins Builder, laforge,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/onomondo-eim/+/42960?usp=email
to look at the new patch set (#2).
The following approvals got outdated and were removed:
Code-Review+1 by laforge, Verified+1 by Jenkins Builder
Change subject: mnesia_db_euicc: rename timer_setparam to timer_rest
......................................................................
mnesia_db_euicc: rename timer_setparam to timer_rest
The function timer_setparam is processing REST API orders
in regular intervals. Naming the timer "timer_rest" makes
more sense.
Change-Id: Icfa203477e044ce2cc312d4b6e2693a97191c61d
---
M src/mnesia_db.erl
M src/mnesia_db_euicc.erl
2 files changed, 5 insertions(+), 5 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/60/42960/2
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42960?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: Icfa203477e044ce2cc312d4b6e2693a97191c61d
Gerrit-Change-Number: 42960
Gerrit-PatchSet: 2
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Attention is currently required from: dexter, laforge.
Hello Jenkins Builder, laforge,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/onomondo-eim/+/42946?usp=email
to look at the new patch set (#5).
The following approvals got outdated and were removed:
Code-Review+1 by laforge, Verified+1 by Jenkins Builder
Change subject: mnesia_db: split functionality into dedicated modules
......................................................................
mnesia_db: split functionality into dedicated modules
The mnesia_db module is responsible to handle three different tables
with different scope. Let's split the functionality into separate
modules to make the code easier to maintain.
Change-Id: Ifc649337ab7ce7eb9dc602a1439293130f002f41
Related: SYS#8100
---
M doc/database.md
A include/mnesia_db_euicc.hrl
A include/mnesia_db_rest.hrl
A include/mnesia_db_work.hrl
M src/crypto_utils.erl
M src/esipa_asn1_handler.erl
M src/esipa_asn1_handler_utils.erl
M src/esipa_asn1_http_handler.erl
M src/esipa_rest_utils.erl
M src/mnesia_db.erl
A src/mnesia_db_euicc.erl
A src/mnesia_db_rest.erl
A src/mnesia_db_work.erl
M src/rest_handler.erl
14 files changed, 933 insertions(+), 857 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/46/42946/5
--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/42946?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: Ifc649337ab7ce7eb9dc602a1439293130f002f41
Gerrit-Change-Number: 42946
Gerrit-PatchSet: 5
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
dexter has abandoned this change. ( https://gerrit.osmocom.org/c/pysim/+/42733?usp=email )
Change subject: cosmetic: remove excess linebreaks
......................................................................
Abandoned
Yes. I think it is the best to abandon this patch.
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42733?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: abandon
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I2272abcdbba0e57c5118b69bc9398cd909a469b5
Gerrit-Change-Number: 42733
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-CC: osmith <osmith(a)sysmocom.de>
laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/42782?usp=email )
Change subject: usb: properly handle data toggle bit
......................................................................
usb: properly handle data toggle bit
Same config SetConfig is currently not properly handled and stale toggle
bits lead to weird transfers until USB resyncs because the asf4 code itself
does not properly handle the toggle bit.
- USB 2.0 §9.4.5 states that ClearFeature(ENDPOINT_HALT) unconditionally
resets the data toggle to DATA0
- USB 2.0 §9.1.1.5 demands toggle reset even when the same config/interface
is selected
The old code was only doing a proper reset upon receiving a bus reset,
but the actual state reset path outlined in the spec is the set config command.
The easy fix here is to split the existing reset code which already does
everything we need into two parts for the actual usb reset and SetConfig.
The current halt clear code only resets DTGL if the endpoint is
actually halted and a fix is a bit more complicated.
_usb_d_dev_ep_stall_clr() is also called from the SETUP-packet cleanup
path in hal_usb_device.c
_usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR);
_usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_CLR);
This runs on every SETUP packet as defensive cleanup of any
leftover stall from a previous failed transfer. That might be why the
asf4 usb code is wrong, because a toggle reset here breaks SETUP.
So the unconditional DTGL reset for halt clearing must therefore happen
in _usb_d_ep_halt_clr itself, which is only reached via the ClearFeature
host request (usbdc_clear_ftr_req -> usb_d_ep_halt(HALT_CLR)),
using a small HPL helper function.
Closes:OS#7016
Change-Id: I5dbca9bd2212407108b44815ecf566fc9c22336d
---
M sysmoOCTSIM/hal/include/hpl_usb_device.h
M sysmoOCTSIM/hal/src/hal_usb_device.c
M sysmoOCTSIM/hpl/usb/hpl_usb.c
M sysmoOCTSIM/usb/device/usbdc.c
4 files changed, 77 insertions(+), 2 deletions(-)
Approvals:
laforge: Looks good to me, approved; Verified
diff --git a/sysmoOCTSIM/hal/include/hpl_usb_device.h b/sysmoOCTSIM/hal/include/hpl_usb_device.h
index 43dd17f..b174abb 100644
--- a/sysmoOCTSIM/hal/include/hpl_usb_device.h
+++ b/sysmoOCTSIM/hal/include/hpl_usb_device.h
@@ -324,6 +324,17 @@
int32_t _usb_d_dev_ep_stall(const uint8_t ep, const enum usb_ep_stall_ctrl ctrl);
/**
+ * \brief Set USB device endpoint data toggle (DTGL) to DATA0 or DATA1
+ * \param[in] ep Endpoint address (with direction bit).
+ * \param[in] tgl 0 = DATA0, non-zero = DATA1.
+ * \return 0 on success, negative on error.
+ *
+ * USB 2.0 §9.4.5: ClearFeature(ENDPOINT_HALT) MUST unconditionally
+ * reinitialize the data toggle to DATA0.
+ */
+int32_t _usb_d_dev_ep_set_toggle(const uint8_t ep, uint8_t tgl);
+
+/**
* \brief Read setup request data from specific endpoint
* \param[in] ep Endpoint address.
* \param[out] req_buf Pointer to buffer to locate the setup packet.
diff --git a/sysmoOCTSIM/hal/src/hal_usb_device.c b/sysmoOCTSIM/hal/src/hal_usb_device.c
index aa80ede..a9a22f0 100644
--- a/sysmoOCTSIM/hal/src/hal_usb_device.c
+++ b/sysmoOCTSIM/hal/src/hal_usb_device.c
@@ -536,6 +536,12 @@
if (ep_index < 0) {
return -USB_ERR_PARAM;
}
+ /* USB 2.0 §9.4.5: ClearFeature(ENDPOINT_HALT) MUST reset data toggle.
+ * This is the only caller that comes from host ClearFeature;
+ * SETUP-cleanup path in usb_d_cb_trans_setup() which also
+ * calls _usb_d_dev_ep_stall(STALL_CLR) must NOT touch DTGL */
+ _usb_d_dev_ep_set_toggle(ep, 0);
+
if (_usb_d_dev_ep_stall(ep, USB_EP_STALL_GET)) {
rc = _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR);
if (rc < 0) {
diff --git a/sysmoOCTSIM/hpl/usb/hpl_usb.c b/sysmoOCTSIM/hpl/usb/hpl_usb.c
index ed9ef62..d743bf6 100644
--- a/sysmoOCTSIM/hpl/usb/hpl_usb.c
+++ b/sysmoOCTSIM/hpl/usb/hpl_usb.c
@@ -1734,6 +1734,16 @@
/* By default, IN endpoint will NAK all token. */
_usbd_ep_set_in_rdy(epn, 1, false);
_usbd_ep_clear_bank_status(epn, 1);
+ /* USB 2.0 §9.4.5: Halt feature reset after SetConfiguration() or SetInterface()
+ * Bus reset already clears STALLRQ in HW but same-config SetConfiguration
+ * does not trigger a bus reset, so clear in software. */
+ _usbd_ep_set_stall(epn, 1, false);
+ /* USB 2.0 §9.1.1.5 / §5.8.5: data toggle must start at DATA0
+ * when the endpoint is configured by SetConfiguration /
+ * SetInterface. SAM D5x/E5x DS60001507 §38.6.2.4 and §38.6.2.2 list
+ * what the hardware clears on bus reset and on endpoint
+ * disable, EPSTATUS.DTGLIN/OUT are NOT in either list, so we must do it. */
+ _usbd_ep_set_toggle(epn, 1, 0);
} else {
/* prevents init->enable->disable->enable again from working without reinit...*/
@@ -1749,6 +1759,10 @@
/* By default, OUT endpoint will NAK all token. */
_usbd_ep_set_out_rdy(epn, 0, false);
_usbd_ep_clear_bank_status(epn, 0);
+ /* USB 2.0 §9.4.5: Halt feature reset by every SetConfig / SetInterface */
+ _usbd_ep_set_stall(epn, 0, false);
+ /* USB 2.0 §9.1.1.5 / §5.8.5: data toggle must start at DATA0 when the endpoint is configured. */
+ _usbd_ep_set_toggle(epn, 0, 0);
}
return USB_OK;
@@ -1807,6 +1821,7 @@
{
uint8_t epn = USB_EP_GET_N(ept->ep);
bool is_stalled = _usbd_ep_is_stalled(epn, dir);
+
if (!is_stalled) {
return ERR_NONE;
}
@@ -1814,6 +1829,13 @@
_usbd_ep_int_dis(epn, USB_DEVICE_EPINTFLAG_STALL0 << dir);
if (_usbd_ep_is_stall_sent(epn, dir)) {
_usbd_ep_ack_stall(epn, dir);
+ /* USB 2.0 §9.4.5: ClearFeature(ENDPOINT_HALT) "always results
+ * in the data toggle being reinitialized to DATA0". Only on
+ * actual stall clear -- this function is also called from the
+ * routine SETUP-packet cleanup in hal_usb_device.c, where
+ * clearing the toggle would break in-flight control transfer
+ * sequencing. Session-state DTGL reset is handled separately
+ * in _usb_d_dev_ep_enable. */
_usbd_ep_set_toggle(epn, dir, 0);
}
if (_usb_d_dev_ep_is_ctrl(ept)) {
@@ -1847,6 +1869,18 @@
return rc;
}
+int32_t _usb_d_dev_ep_set_toggle(const uint8_t ep, uint8_t tgl)
+{
+ uint8_t epn = USB_EP_GET_N(ep);
+ bool dir = USB_EP_GET_DIR(ep);
+
+ if (epn > CONF_USB_D_MAX_EP_N) {
+ return -USB_ERR_PARAM;
+ }
+ _usbd_ep_set_toggle(epn, dir, tgl);
+ return ERR_NONE;
+}
+
/**
* \brief Finish the transaction and invoke callback
* \param[in, out] ept Pointer to endpoint information.
diff --git a/sysmoOCTSIM/usb/device/usbdc.c b/sysmoOCTSIM/usb/device/usbdc.c
index 38aa0e0..a02cf92 100644
--- a/sysmoOCTSIM/usb/device/usbdc.c
+++ b/sysmoOCTSIM/usb/device/usbdc.c
@@ -448,13 +448,32 @@
}
/**
+ * \brief soft session-state reset.
+ *
+ * Called by usbdc_unconfig and usbdc_set_config. Stops
+ * card-side SERCOM USARTs and freezes SysTick driven timeouts.
+ * The was_unconfigured_flag tells the main loop to run the other half of the cleanup/reset.
+ *
+ * This is only the "session state" half of a bus reset.
+ * Bus reset additionally tears down EP existence (EPCFG.EPTYPE) via
+ * usbdc_unconfig's USBDF_DISABLE loop, a SetConfig does not need that (and usually happens after the reset).
+ */
+static void usbdc_softreset(void)
+{
+ reset_all_stuff_irq();
+ was_unconfigured_flag = true;
+}
+
+/**
* \brief Unconfig, close all interfaces
*/
static void usbdc_unconfig(void)
{
- reset_all_stuff_irq();
- was_unconfigured_flag = true;
+ usbdc_softreset();
+ /* In addition to the soft reset, tear down per-function state: USBDF_DISABLE calls the class driver
+ * (e.g. ccid_df_disable -> usb_d_ep_deinit per EP), which clears EPCFG.EPTYPE etc.
+ * Right thing to do for for USB bus reset and for SetConfig(0), but NOT for a same-config SetConfig. */
struct usbdf_driver *func = (struct usbdf_driver *)usbdc.func_list.head;
while (NULL != func) {
func->ctrl(func, USBDF_DISABLE, NULL);
@@ -481,6 +500,11 @@
return true;
}
+ /* USB 2.0 §9.1.1.5 / §9.4.5 a non-zero SetConfiguration unconditionally resets endpoint state. */
+ if (usbdc.cfg_value != 0) {
+ usbdc_softreset();
+ }
+
#if CONF_USBD_HS_SP
if (usb_d_get_speed() == USB_SPEED_HS && usbdc.desces.hs) {
cfg_desc = usb_find_cfg_desc(usbdc.desces.hs->sod, usbdc.desces.hs->eod, cfg_value);
--
To view, visit https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/42782?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-Change-Id: I5dbca9bd2212407108b44815ecf566fc9c22336d
Gerrit-Change-Number: 42782
Gerrit-PatchSet: 3
Gerrit-Owner: Hoernchen <ewild(a)sysmocom.de>
Gerrit-Reviewer: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>