Looking at sending GSUP messages between MSCs via an HLR acting as forwarding
agent, I see that the current decision for GSUP message consumption is
suboptimal:

Depending on the message type sent and received, libvlr of osmo-msc forwards
GSUP messages to the MSC code, and there, again, depending on the message type,
specific callbacks get invoked.

See vlr_gsupc_read_cb() and msc_vlr_route_gsup_msg().

In current osmo-msc it might seem to make sense to first resolve the IMSI to a
vlr_subscr in vlr.c. But if osmo-msc acts as a Handover target for an inter-MSC
Handover, it should be able to handle unknown IMSIs. Also, should we ever go
for a separate SMSC process, the VLR as first stage makes no sense. Finding a
vlr_subscr is a one-liner with vlr_subscr_find_by_imsi().

I would much rather have an explicit destination entity advertised in the GSUP
messages, and an explicit common GSUP MUX stage. In other words, the VLR of
osmo-msc shouldn't act as a GSUP forwarder, it should merely be one of the GSUP
consumers, and shouldn't even be involved when the messages are intended for
inter-MSC, for USSD or for SMS use.

And finally, for GSUP error responses, for example a report that a specific
target could not be reached, it may not be possible to trivially derive the
right GSUP message consumer from the GSUP message (like "Routing Error").

Going towards that idea, I have put in place the following in my temporary dev
source tree:

        enum osmo_gsup_entity {
                OSMO_GSUP_ENTITY_NONE = 0,
                OSMO_GSUP_ENTITY_HLR,
                OSMO_GSUP_ENTITY_VLR,
                OSMO_GSUP_ENTITY_ESME,
                OSMO_GSUP_ENTITY_SMSC,
                OSMO_GSUP_ENTITY_USSD, // FIXME: what's an "ESME"/"SMSC" for 
USSD?
                OSMO_GSUP_ENTITY_MSC_A,
                OSMO_GSUP_ENTITY_MSC_B,
                OSMO_GSUP_ENTITY_COUNT,
        };

        struct osmo_gsup_message {
                [...]
                enum osmo_gsup_entity           source_entity;
                enum osmo_gsup_entity           destination_entity;
                [...]
        };

For calling the right rx_cb, we would need only an explicit target kind, but
for returning errors it is better to also include the source entity kind
explicitly.

A gsup_client_mux API:

        struct gsup_client_mux_rx_cb {
                int (* func )(struct gsup_client_mux *gcm, void *data, const 
struct osmo_gsup_message *msg);
                void *data;
        };

        struct gsup_client_mux {
                struct osmo_gsup_client *gsup_client;

                /* Target clients by enum osmo_gsup_entity */
                struct gsup_client_mux_rx_cb rx_cb[OSMO_GSUP_ENTITY_COUNT];
        };

        int gsup_client_mux_init(struct gsup_client_mux *gcm, struct 
osmo_gsup_client *gsup_client);

        int gsup_client_mux_tx(struct gsup_client_mux *gcm, const struct 
osmo_gsup_message *gsup_msg);
        void gsup_client_mux_tx_error_reply(struct gsup_client_mux *gcm, const 
struct osmo_gsup_message *gsup_orig,
                                            enum gsm48_gmm_cause cause);

For backwards compat, we would still need to do target classification by
message type, but only if no explicit destination_entity is set:

        static enum osmo_gsup_entity gsup_client_mux_classify(struct 
gsup_client_mux *gcm,
                                                              const struct 
osmo_gsup_message *gsup)
        {
                if (gsup->destination_entity)
                        return gsup->destination_entity;

                /* Legacy message that lacks an explicit target entity. Guess 
by message type for backwards compat: */
                switch (gsup_msg->message_type) {
                case OSMO_GSUP_MSGT_PROC_SS_REQUEST:
                case OSMO_GSUP_MSGT_PROC_SS_RESULT:
                case OSMO_GSUP_MSGT_PROC_SS_ERROR:
                        return OSMO_GSUP_ENTITY_USSD;

                case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR:
                case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT:
                case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR:
                case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT:
                case OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST:
                        return OSMO_GSUP_ENTITY_SMSC;

                default:
                        /* osmo-hlr capable of forwarding inter-MSC messages 
always includes the target entity, so any
                         * other legacy message is for the VLR. */
                        return OSMO_GSUP_ENTITY_VLR;
                }
        }

We'd have:

  HLR <-> VLR
  ESME <-> SMSC
  USSD <-> USSD (names??)
  MSC_A <-> MSC_B

Thanks for your thoughts.

~N

Attachment: signature.asc
Description: PGP signature

Reply via email to