@@ -46,11 +46,24 @@
SCCP_CONNECTION_STATE_SETUP_ERROR,
};
+struct sccp_variant {
+ uint8_t ai_nb; /* National or reserved bit */
+ uint8_t ai_gti; /* GTI mask */
+ uint8_t ai_pc_ind; /* Point code indicator mask */
+ uint8_t ai_ssn_ind; /* SSN indicator mask */
+ uint8_t ai_route; /* Route type mask */
+ uint8_t pc_len; /* Point code length */
+ uint8_t pc_first; /* whether the pointcode comes before the SSN */
+};
+
struct sockaddr_sccp {
- sa_family_t sccp_family; /* AF_SCCP in the future??? */
+ sa_family_t sccp_family; /* AF_SCCP in the future??? */
+
+ int use_ssn;
uint8_t sccp_ssn; /* subssystem number for routing */
- /* TODO fill in address indicator... if that is ever needed */
+ int nb; /* National bit (8) */
+ int route_on_ssn; /* Force routing on SSN instead of GTI */
/* optional gti information */
uint8_t *gti;
@@ -60,7 +73,7 @@
uint8_t gti_ind;
int use_poi;
- uint8_t poi[2];
+ uint8_t poi[3]; /* Allows ITU 14bit and ANSI 24bit */
/* not sure about these */
/* uint8_t sccp_class; */
@@ -70,9 +83,8 @@
* parsed structure of an address
*/
struct sccp_address {
- struct sccp_called_party_address address;
uint8_t ssn;
- uint8_t poi[2];
+ uint8_t poi[3]; /* Allows ITU 14bit and ANSI 24bit */
uint8_t *gti_data;
int gti_len;
@@ -103,6 +115,8 @@
int incoming;
};
+extern struct sccp_variant sccp_variant[];
+
/**
* system functionality to implement on top of any other transport layer:
* call sccp_system_incoming for incoming data (from the network)
@@ -122,7 +136,7 @@
int sccp_connection_free(struct sccp_connection *connection);
/**
- * internal..
+ * internal..
*/
int sccp_connection_force_free(struct sccp_connection *conn);
@@ -157,6 +171,7 @@
int sccp_set_read(const struct sockaddr_sccp *sock,
int (*read_cb)(struct msgb *msgb, unsigned int, void *user_data),
void *user_data);
+void sccp_set_variant(int variant);
/* generic sock addresses */
extern const struct sockaddr_sccp sccp_ssn_bssap;
@@ -26,6 +26,12 @@
#include <osmocom/core/endian.h>
+/* Which variant of SCCP we're using */
+enum {
+ SCCP_VARIANT_ITU,
+ SCCP_VARIANT_ANSI
+};
+
/* Table 1/Q.713 - SCCP message types */
enum sccp_message_types {
SCCP_MSG_TYPE_CR = 1,
@@ -46,16 +46,40 @@
.sccp_ssn = SCCP_SSN_BSSAP,
};
+struct sccp_variant sccp_variant[] = {
+ [SCCP_VARIANT_ITU] = {
+ .ai_nb = 0x80,
+ .ai_gti = 0x3c,
+ .ai_pc_ind = 0x01,
+ .ai_ssn_ind = 0x02,
+ .ai_route = 0x40,
+ .pc_len = 2,
+ .pc_first = 1
+ },
+ [SCCP_VARIANT_ANSI] = {
+ .ai_nb = 0x80,
+ .ai_gti = 0x3c,
+ .ai_pc_ind = 0x02,
+ .ai_ssn_ind = 0x01,
+ .ai_route = 0x40,
+ .pc_len = 3,
+ .pc_first = 0,
+ }
+};
+
struct sccp_system {
/* layer3 -> layer2 */
void (*write_data)(struct sccp_connection *conn, struct msgb *data,
void *gctx, void *ctx);
void *write_context;
+
+ int variant;
};
static struct sccp_system sccp_system = {
.write_data = NULL,
+ .variant = SCCP_VARIANT_ITU
};
struct sccp_data_callback {
@@ -105,11 +129,13 @@
*/
static int copy_address(struct sccp_address *addr, uint8_t offset, struct msgb *msgb)
{
- struct sccp_called_party_address *party;
-
int room = msgb_l2len(msgb) - offset;
- uint8_t read = 0;
+
+ uint8_t *data;
+ uint8_t read = 1;
uint8_t length;
+ uint8_t ai;
+ uint8_t pc_len = sccp_variant[sccp_system.variant].pc_len;
if (room <= 0) {
LOGP(DSCCP, LOGL_ERROR, "Not enough room for an address: %u\n", room);
@@ -122,36 +148,48 @@
return -1;
}
+ data = msgb->l2h + offset + 1;
+ ai = data[0];
+ data++;
- party = (struct sccp_called_party_address *)(msgb->l2h + offset + 1);
- if (party->point_code_indicator) {
- if (length <= read + 2) {
- LOGP(DSCCP, LOGL_ERROR, "POI does not fit %u\n", length);
- return -1;
- }
+#define PARSE_POI \
+ do { \
+ if (ai & sccp_variant[sccp_system.variant].ai_pc_ind) { \
+ if (length <= read + pc_len) { \
+ LOGP(DSCCP, LOGL_ERROR, "POI does not fit %u\n", length); \
+ return -1; \
+ } \
+ memcpy(&addr->poi, &data[read], pc_len); \
+ read += pc_len; \
+ } \
+ } while (0)
+#define PARSE_SSN \
+ do { \
+ if (ai & sccp_variant[sccp_system.variant].ai_ssn_ind) { \
+ if (length <= read + 1) { \
+ LOGP(DSCCP, LOGL_ERROR, "SSN does not fit %u\n", length); \
+ return -1; \
+ } \
+ addr->ssn = data[read]; \
+ read += 1; \
+ } \
+ } while (0)
- memcpy(&addr->poi, &party->data[read], 2);
- read += 2;
- }
-
- if (party->ssn_indicator) {
- if (length <= read + 1) {
- LOGP(DSCCP, LOGL_ERROR, "SSN does not fit %u\n", length);
- return -1;
- }
-
- addr->ssn = party->data[read];
- read += 1;
+ if (sccp_variant[sccp_system.variant].pc_first) {
+ PARSE_POI;
+ PARSE_SSN;
+ } else {
+ PARSE_SSN;
+ PARSE_POI;
}
/* copy the GTI over */
- if (party->global_title_indicator) {
- addr->gti_len = length - read - 1;
- addr->gti_data = &party->data[read];
+ if (ai & sccp_variant[sccp_system.variant].ai_gti) {
+ addr->gti_len = length - read;
+ addr->gti_data = &data[read];
}
- addr->address = *party;
return 0;
}
@@ -173,7 +211,6 @@
uint8_t length = msgb->l2h[offset + read + 1];
read += 2 + length;
-
if (room <= read) {
LOGP(DSCCP, LOGL_ERROR,
@@ -486,28 +523,43 @@
int sccp_create_sccp_addr(struct msgb *msg, const struct sockaddr_sccp *sock)
{
uint8_t *len, *ai, *gti;
+ uint8_t *poi;
+ uint8_t pc_len = sccp_variant[sccp_system.variant].pc_len;
len = msgb_put(msg, 1);
ai = msgb_put(msg, 1);
+ if (sock->gti) ai[0] = (sock->gti_ind & 0x0f) << 2;
+ if (sock->route_on_ssn || !sock->gti) ai[0] |= sccp_variant[sccp_system.variant].ai_route;
- if (sock->gti)
- ai[0] = 0 << 6 | (sock->gti_ind & 0x0f) << 2 | 1 << 1;
- else
- ai[0] = 1 << 6 | 1 << 1;
+ /* National/reserved bit */
+ if (sock->nb) ai[0] |= sccp_variant[sccp_system.variant].ai_nb;
- /* store a point code */
- if (sock->use_poi) {
- uint8_t *poi;
+ /* Pointcode ind */
+ if (sock->use_poi) ai[0] |= sccp_variant[sccp_system.variant].ai_pc_ind;
- ai[0] |= 0x01;
- poi = msgb_put(msg, 2);
- poi[0] = sock->poi[0];
- poi[1] = sock->poi[1];
+ /* SSN ind */
+ ai[0] |= sccp_variant[sccp_system.variant].ai_ssn_ind;
+
+#define ADD_POI \
+ do { \
+ if (sock->use_poi) { \
+ poi = msgb_put(msg, pc_len); \
+ if (!poi) return -1; \
+ memcpy(poi, &sock->poi[0], pc_len); \
+ } \
+ } while (0)
+
+#define ADD_SSN \
+ msgb_v_put(msg, sock->sccp_ssn)
+
+ if (sccp_variant[sccp_system.variant].pc_first) {
+ ADD_POI;
+ ADD_SSN;
+ } else {
+ ADD_SSN;
+ ADD_POI;
}
-
- /* copy the SSN */
- msgb_v_put(msg, sock->sccp_ssn);
/* copy the gti if it is present */
gti = msgb_put(msg, sock->gti_len);
@@ -1225,6 +1277,11 @@
return 0;
}
+void sccp_set_variant(int variant)
+{
+ sccp_system.variant = variant;
+}
+
/* oh my god a real SCCP packet. need to dispatch it now */
int sccp_system_incoming(struct msgb *msgb)
{