aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm/gsup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsm/gsup.c')
-rw-r--r--src/gsm/gsup.c125
1 files changed, 115 insertions, 10 deletions
diff --git a/src/gsm/gsup.c b/src/gsm/gsup.c
index ef33ed08..4f0a1b5f 100644
--- a/src/gsm/gsup.c
+++ b/src/gsm/gsup.c
@@ -103,6 +103,10 @@ const struct value_string osmo_gsup_message_type_names[] = {
OSMO_VALUE_STRING(OSMO_GSUP_MSGT_ROUTING_ERROR),
+ OSMO_VALUE_STRING(OSMO_GSUP_MSGT_EPDG_TUNNEL_REQUEST),
+ OSMO_VALUE_STRING(OSMO_GSUP_MSGT_EPDG_TUNNEL_RESULT),
+ OSMO_VALUE_STRING(OSMO_GSUP_MSGT_EPDG_TUNNEL_ERROR),
+
{ 0, NULL }
};
@@ -122,6 +126,62 @@ int osmo_gsup_get_err_msg_type(enum osmo_gsup_message_type type_in)
return OSMO_GSUP_TO_MSGT_ERROR(type_in);
}
+static int decode_pdp_address(const uint8_t *data, size_t data_len, struct osmo_gsup_pdp_info *pdp_info)
+{
+ const struct gsm48_pdp_address *pdp_addr = (const struct gsm48_pdp_address *)data;
+ /* Explicitly pre-nitialize them to AF_UNSPEC to signal they are empty: */
+ pdp_info->pdp_address[0].u.sa.sa_family = AF_UNSPEC;
+ pdp_info->pdp_address[1].u.sa.sa_family = AF_UNSPEC;
+
+ if (data_len < 2)
+ return -GMM_CAUSE_PROTO_ERR_UNSPEC;
+
+ pdp_info->pdp_type_org = pdp_addr->organization;
+ pdp_info->pdp_type_nr = pdp_addr->type;
+
+ if (pdp_info->pdp_type_org != PDP_TYPE_ORG_IETF)
+ return -GMM_CAUSE_PROTO_ERR_UNSPEC;
+
+ /* Skip type-org + type-nr for easy calculations below: */
+ data_len -= 2;
+
+ switch (pdp_info->pdp_type_nr) {
+ case PDP_TYPE_N_IETF_IPv4:
+ if (data_len == 0)
+ return 0; /* empty, marked as AF_UNSET. */
+ if (data_len != sizeof(pdp_addr->ietf.v4))
+ return -GMM_CAUSE_PROTO_ERR_UNSPEC;
+ pdp_info->pdp_address[0].u.sa.sa_family = AF_INET;
+ pdp_info->pdp_address[0].u.sin.sin_addr.s_addr = pdp_addr->ietf.v4;
+ return 0;
+ case PDP_TYPE_N_IETF_IPv6:
+ if (data_len == 0)
+ return 0; /* empty, marked as AF_UNSET. */
+ if (data_len != sizeof(pdp_addr->ietf.v6))
+ return -GMM_CAUSE_PROTO_ERR_UNSPEC;
+ pdp_info->pdp_address[0].u.sa.sa_family = AF_INET6;
+ memcpy(&pdp_info->pdp_address[0].u.sin6.sin6_addr,
+ pdp_addr->ietf.v6,
+ sizeof(pdp_addr->ietf.v6));
+ return 0;
+ case PDP_TYPE_N_IETF_IPv4v6:
+ if (data_len == 0)
+ return 0; /* empty, marked as AF_UNSET. */
+ if (data_len != sizeof(pdp_addr->ietf.v4v6))
+ return -GMM_CAUSE_PROTO_ERR_UNSPEC;
+ pdp_info->pdp_address[0].u.sa.sa_family = AF_INET;
+ pdp_info->pdp_address[0].u.sin.sin_addr.s_addr = pdp_addr->ietf.v4v6.v4;
+ pdp_info->pdp_address[1].u.sa.sa_family = AF_INET6;
+ memcpy(&pdp_info->pdp_address[1].u.sin6.sin6_addr,
+ pdp_addr->ietf.v4v6.v6,
+ sizeof(pdp_addr->ietf.v4v6.v6));
+ return 0;
+ default:
+ /* reserved, both pdp_info->pdp_address are preinitialied to AF_UNSET. */
+ return 0;
+ }
+}
+
static int decode_pdp_info(uint8_t *data, size_t data_len,
struct osmo_gsup_pdp_info *pdp_info)
{
@@ -145,9 +205,9 @@ static int decode_pdp_info(uint8_t *data, size_t data_len,
pdp_info->context_id = osmo_decode_big_endian(value, value_len);
break;
- case OSMO_GSUP_PDP_TYPE_IE:
- pdp_info->pdp_type =
- osmo_decode_big_endian(value, value_len) & 0x0fff;
+ case OSMO_GSUP_PDP_ADDRESS_IE:
+ if ((rc = decode_pdp_address(value, value_len, pdp_info)) < 0)
+ return rc;
break;
case OSMO_GSUP_ACCESS_POINT_NAME_IE:
@@ -262,7 +322,7 @@ static int decode_auth_info(uint8_t *data, size_t data_len,
parse_error:
LOGP(DLGSUP, LOGL_ERROR,
- "GSUP IE type %d, length %zu invalid in PDP info\n", iei, value_len);
+ "GSUP IE type %d, length %zu invalid in auth info\n", iei, value_len);
return -1;
}
@@ -353,7 +413,7 @@ int osmo_gsup_decode(const uint8_t *const_data, size_t data_len,
switch (iei) {
case OSMO_GSUP_IMSI_IE:
- case OSMO_GSUP_PDP_TYPE_IE:
+ case OSMO_GSUP_PDP_ADDRESS_IE:
case OSMO_GSUP_ACCESS_POINT_NAME_IE:
case OSMO_GSUP_SRES_IE:
case OSMO_GSUP_KC_IE:
@@ -446,6 +506,11 @@ int osmo_gsup_decode(const uint8_t *const_data, size_t data_len,
gsup_msg->rand = value;
break;
+ case OSMO_GSUP_PCO_IE:
+ gsup_msg->pco = value;
+ gsup_msg->pco_len = value_len;
+ break;
+
case OSMO_GSUP_MSISDN_IE:
gsup_msg->msisdn_enc = value;
gsup_msg->msisdn_enc_len = value_len;
@@ -597,11 +662,45 @@ static void encode_pdp_info(struct msgb *msg, enum osmo_gsup_iei iei,
u8 = pdp_info->context_id;
msgb_tlv_put(msg, OSMO_GSUP_PDP_CONTEXT_ID_IE, sizeof(u8), &u8);
- if (pdp_info->pdp_type) {
- msgb_tlv_put(msg, OSMO_GSUP_PDP_TYPE_IE,
- OSMO_GSUP_PDP_TYPE_SIZE,
- osmo_encode_big_endian(pdp_info->pdp_type | 0xf000,
- OSMO_GSUP_PDP_TYPE_SIZE));
+ if (pdp_info->pdp_type_org == PDP_TYPE_ORG_IETF) {
+ struct gsm48_pdp_address pdp_addr;
+ uint8_t pdp_addr_len = 2;
+ pdp_addr.spare = 0x0f;
+ pdp_addr.organization = pdp_info->pdp_type_org;
+ pdp_addr.type = pdp_info->pdp_type_nr;
+
+ switch (pdp_info->pdp_type_nr) {
+ case PDP_TYPE_N_IETF_IPv4:
+ if (pdp_info->pdp_address[0].u.sa.sa_family == AF_INET) {
+ pdp_addr.ietf.v4 = pdp_info->pdp_address[0].u.sin.sin_addr.s_addr;
+ pdp_addr_len += sizeof(pdp_addr.ietf.v4);
+ }
+ break;
+ case PDP_TYPE_N_IETF_IPv6:
+ if (pdp_info->pdp_address[0].u.sa.sa_family == AF_INET6) {
+ memcpy(pdp_addr.ietf.v6,
+ &pdp_info->pdp_address[0].u.sin6.sin6_addr,
+ sizeof(pdp_addr.ietf.v6));
+ pdp_addr_len += sizeof(pdp_addr.ietf.v6);
+ }
+ break;
+ case PDP_TYPE_N_IETF_IPv4v6:
+ if (pdp_info->pdp_address[0].u.sa.sa_family == AF_INET) {
+ pdp_addr.ietf.v4v6.v4 = pdp_info->pdp_address[0].u.sin.sin_addr.s_addr;
+ pdp_addr_len += sizeof(pdp_addr.ietf.v4v6.v4);
+ }
+ if (pdp_info->pdp_address[0].u.sa.sa_family == AF_INET6) {
+ memcpy(pdp_addr.ietf.v4v6.v6,
+ &pdp_info->pdp_address[1].u.sin6.sin6_addr,
+ sizeof(pdp_addr.ietf.v4v6.v6));
+ pdp_addr_len += sizeof(pdp_addr.ietf.v4v6.v6);
+ }
+ break;
+ }
+
+ msgb_tlv_put(msg, OSMO_GSUP_PDP_ADDRESS_IE,
+ pdp_addr_len,
+ (const uint8_t *)&pdp_addr);
}
if (pdp_info->apn_enc) {
@@ -778,6 +877,11 @@ int osmo_gsup_encode(struct msgb *msg, const struct osmo_gsup_message *gsup_msg)
if (gsup_msg->rand)
msgb_tlv_put(msg, OSMO_GSUP_RAND_IE, 16, gsup_msg->rand);
+ if (gsup_msg->pco && gsup_msg->pco_len > 0) {
+ if (gsup_msg->pco_len > OSMO_GSUP_MAX_PCO_LEN)
+ return -EINVAL;
+ msgb_tlv_put(msg, OSMO_GSUP_PCO_IE, gsup_msg->pco_len, gsup_msg->pco);
+ }
if (gsup_msg->cn_domain) {
uint8_t dn = gsup_msg->cn_domain;
msgb_tlv_put(msg, OSMO_GSUP_CN_DOMAIN_IE, 1, &dn);
@@ -911,6 +1015,7 @@ const struct value_string osmo_gsup_message_class_names[] = {
{ OSMO_GSUP_MESSAGE_CLASS_SMS, "SMS" },
{ OSMO_GSUP_MESSAGE_CLASS_USSD, "USSD" },
{ OSMO_GSUP_MESSAGE_CLASS_INTER_MSC, "Inter-MSC" },
+ { OSMO_GSUP_MESSAGE_CLASS_IPSEC_EPDG, "IPsec-ePDG" },
{}
};