Merge branch 'master' into config_file

Conflicts:
	openbsc/src/vty_interface.c
This commit is contained in:
Harald Welte 2009-08-08 16:08:54 +02:00
commit 3c5cb256c2
20 changed files with 1000 additions and 299 deletions

View File

@ -681,6 +681,11 @@ int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
u_int8_t e1_port1, u_int8_t ts1);
int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
u_int8_t test_nr, u_int8_t auton_report,
u_int8_t *phys_config, u_int16_t phys_config_len);
/* Siemens / BS-11 specific */
int abis_nm_bs11_reset_resource(struct gsm_bts *bts);
int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin);

View File

@ -476,6 +476,7 @@ int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_needed,
int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val);
int rsl_data_request(struct msgb *msg, u_int8_t link_id);
int rsl_relase_request(struct gsm_lchan *lchan, u_int8_t link_id);
/* ip.access specfic RSL extensions */
int rsl_ipacc_bind(struct gsm_lchan *lchan);

View File

@ -3,6 +3,21 @@
/* GSM TS 04.11 definitions */
/* Chapter 5.2.3: SMC-CS states at the network side */
enum gsm411_cp_state {
GSM411_CPS_IDLE = 0,
GSM411_CPS_MM_CONN_PENDING = 1, /* only MT ! */
GSM411_CPS_WAIT_CP_ACK = 2,
GSM411_CPS_MM_ESTABLISHED = 3,
};
/* Chapter 6.2.2: SMR states at the network side */
enum gsm411_rp_state {
GSM411_RPS_IDLE = 0,
GSM411_RPS_WAIT_FOR_RP_ACK = 1,
GSM411_RPS_WAIT_TO_TX_RP_ACK = 3,
};
/* Chapter 8.1.2 (refers to GSM 04.07 Chapter 11.2.3.1.1 */
#define GSM411_PDISC_SMS 0x09
@ -16,6 +31,19 @@ enum gsm411_cp_ie {
GSM411_CP_IE_CAUSE = 0x02, /* 8.1.4.2. */
};
/* Section 8.1.4.2 / Table 8.2 */
enum gsm411_cp_cause {
GSM411_CP_CAUSE_NET_FAIL = 17,
GSM411_CP_CAUSE_CONGESTION = 22,
GSM411_CP_CAUSE_INV_TRANS_ID = 81,
GSM411_CP_CAUSE_SEMANT_INC_MSG = 95,
GSM411_CP_CAUSE_INV_MAND_INF = 96,
GSM411_CP_CAUSE_MSGTYPE_NOTEXIST= 97,
GSM411_CP_CAUSE_MSG_INCOMP_STATE= 98,
GSM411_CP_CAUSE_IE_NOTEXIST = 99,
GSM411_CP_CAUSE_PROTOCOL_ERR = 111,
};
/* Chapter 8.2.2 */
#define GSM411_MT_RP_DATA_MO 0x00
#define GSM411_MT_RP_DATA_MT 0x01
@ -30,6 +58,41 @@ enum gsm411_rp_ie {
GSM411_IE_RP_CAUSE = 0x42, /* 8.2.5.4 */
};
/* Chapter 8.2.5.4 Table 8.4 */
enum gsm411_rp_cause {
/* valid only for MO */
GSM411_RP_CAUSE_MO_NUM_UNASSIGNED = 1,
GSM411_RP_CAUSE_MO_OP_DET_BARR = 8,
GSM411_RP_CAUSE_MO_CALL_BARRED = 10,
GSM411_RP_CAUSE_MO_SMS_REJECTED = 21,
GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER = 27,
GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR = 28,
GSM411_RP_CAUSE_MO_FACILITY_REJ = 29,
GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR = 30,
GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER = 38,
GSM411_RP_CAUSE_MO_TEMP_FAIL = 41,
GSM411_RP_CAUSE_MO_CONGESTION = 42,
GSM411_RP_CAUSE_MO_RES_UNAVAIL = 47,
GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR = 50,
GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL = 69,
GSM411_RP_CAUSE_MO_INTERWORKING = 127,
/* valid only for MT */
GSM411_RP_CAUSE_MT_MEM_EXCEEDED = 22,
/* valid for both directions */
GSM411_RP_CAUSE_INV_TRANS_REF = 81,
GSM411_RP_CAUSE_SEMANT_INC_MSG = 95,
GSM411_RP_CAUSE_INV_MAND_INF = 96,
GSM411_RP_CAUSE_MSGTYPE_NOTEXIST = 97,
GSM411_RP_CAUSE_MSG_INCOMP_STATE = 98,
GSM411_RP_CAUSE_IE_NOTEXIST = 99,
GSM411_RP_CAUSE_PROTOCOL_ERR = 111,
};
/* Chapter 10: Timers */
#define GSM411_TMR_TR1M 40 /* 35 < x < 45 seconds */
#define GSM411_TMR_TRAM 30 /* 25 < x < 35 seconds */
#define GSM411_TMR_TR2M 15 /* 12 < x < 20 seconds */
/* Chapter 8.2.1 */
struct gsm411_rp_hdr {
u_int8_t len;
@ -46,29 +109,6 @@ enum sms_alphabet {
DCS_8BIT_DATA,
};
/* SMS submit PDU */
struct sms_submit {
u_int8_t *smsc;
u_int8_t mti:2;
u_int8_t vpf:2;
u_int8_t msg_ref;
u_int8_t pid;
u_int8_t dcs;
u_int8_t *vp;
u_int8_t ud_len;
u_int8_t *user_data;
/* interpreted */
u_int8_t mms:1;
u_int8_t sri:1;
u_int8_t udhi:1;
u_int8_t rp:1;
enum sms_alphabet alphabet;
char dest_addr[20+1]; /* DA LV is 12 bytes max, i.e. 10 bytes BCD == 20 bytes string */
unsigned long validity_mins;
char decoded[256];
};
/* GSM 03.40 / Chapter 9.2.3.1: TP-Message-Type-Indicator */
#define GSM340_SMS_DELIVER_SC2MS 0x00
#define GSM340_SMS_DELIVER_REP_MS2SC 0x00
@ -141,23 +181,22 @@ struct sms_submit {
#define GSM338_DCS_1111_CLASS2_SIM 2
#define GSM338_DCS_1111_CLASS3_TE 3 /* See TS 07.05 */
/* SMS deliver PDU */
struct sms_deliver {
u_int8_t mti:2; /* message type indicator */
u_int8_t mms:1; /* more messages to send */
u_int8_t rp:1; /* reply path */
u_int8_t udhi:1; /* user data header indicator */
u_int8_t sri:1; /* status report indication */
u_int8_t *orig_addr; /* originating address */
u_int8_t pid; /* protocol identifier */
u_int8_t dcs; /* data coding scheme */
/* service centre time stamp */
u_int8_t ud_len; /* user data length */
u_int8_t *user_data; /* user data */
u_int8_t msg_ref; /* message reference */
u_int8_t *smsc;
u_int8_t mti:2;
u_int8_t rd:1;
u_int8_t vpf:2;
u_int8_t srr:1;
u_int8_t udhi:1;
u_int8_t rp:1;
u_int8_t msg_ref;
u_int8_t *orig_addr;
u_int8_t pid;
u_int8_t dcs;
u_int8_t vp;
u_int8_t ud_len;
u_int8_t *user_data;
};
struct msgb;
@ -166,7 +205,4 @@ int gsm0411_rcv_sms(struct msgb *msg);
int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms);
struct msgb *gsm411_msgb_alloc(void);
int gsm0411_sendmsg(struct msgb *msg);
#endif

View File

@ -80,7 +80,7 @@ typedef int gsm_cbfn(unsigned int hooknum,
* Use the channel. As side effect the lchannel recycle timer
* will be started.
*/
#define LCHAN_RELEASE_TIMEOUT 10, 0
#define LCHAN_RELEASE_TIMEOUT 20, 0
#define use_lchan(lchan) \
do { lchan->use_count++; \
DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
@ -106,44 +106,6 @@ struct gsm_subscriber;
struct gsm_mncc;
struct rtp_socket;
/* One transaction */
struct gsm_trans {
/* Entry in list of all transactions */
struct llist_head entry;
/* The protocol within which we live */
u_int8_t protocol;
/* The current transaction ID */
u_int8_t transaction_id;
/* To whom we belong, unique identifier of remote MM entity */
struct gsm_subscriber *subscr;
/* The LCHAN that we're currently using to transmit messages */
struct gsm_lchan *lchan;
/* reference from MNCC or other application */
u_int32_t callref;
union {
struct {
/* current call state */
int state;
/* current timer and message queue */
int Tcurrent; /* current CC timer */
int T308_second; /* used to send release again */
struct timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
} cc;
struct {
} sms;
};
};
/* Network Management State */
struct gsm_nm_state {
u_int8_t operational;
@ -398,7 +360,18 @@ struct gsm_sms {
struct gsm_subscriber *sender;
struct gsm_subscriber *receiver;
unsigned char header[SMS_HDR_SIZE];
unsigned long validity_minutes;
u_int8_t reply_path_req;
u_int8_t status_rep_req;
u_int8_t ud_hdr_ind;
u_int8_t protocol_id;
u_int8_t data_coding_scheme;
u_int8_t msg_ref;
char dest_addr[20+1]; /* DA LV is 12 bytes max, i.e. 10 bytes
* BCD == 20 bytes string */
u_int8_t user_data_len;
u_int8_t user_data[SMS_TEXT_SIZE];
char text[SMS_TEXT_SIZE];
};
@ -425,7 +398,7 @@ enum gsm_e1_event {
void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr,
u_int8_t e1_ts, u_int8_t e1_ts_ss);
enum gsm_bts_type parse_btstype(char *arg);
enum gsm_bts_type parse_btstype(const char *arg);
const char *btstype2str(enum gsm_bts_type type);
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
struct gsm_bts *start_bts);

View File

@ -50,6 +50,7 @@ enum gsm_subscriber_field {
GSM_SUBSCRIBER_IMSI,
GSM_SUBSCRIBER_TMSI,
GSM_SUBSCRIBER_EXTENSION,
GSM_SUBSCRIBER_ID,
};
enum gsm_subscriber_update_reason {
@ -66,6 +67,8 @@ struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net,
const char *imsi);
struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
const char *ext);
struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
unsigned long long id);
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
void subscr_put_channel(struct gsm_lchan *lchan);
void subscr_get_channel(struct gsm_subscriber *subscr,

View File

@ -38,6 +38,7 @@ enum signal_subsystems {
SS_ABISIP,
SS_NM,
SS_LCHAN,
SS_SUBSCR,
};
/* SS_PAGING signals */
@ -45,6 +46,13 @@ enum signal_paging {
S_PAGING_COMPLETED,
};
/* SS_SMS signals */
enum signal_sms {
S_SMS_SUBMITTED, /* A SMS has been successfully submitted to us */
S_SMS_DELIVERED, /* A SMS has been successfully delivered to a MS */
S_SMS_SMMA, /* A MS tells us it has more space available */
};
/* SS_ABISIP signals */
enum signal_abisip {
S_ABISIP_BIND_ACK,
@ -57,6 +65,7 @@ enum signal_nm {
S_NM_FAIL_REP, /* GSM 12.21 failure event report */
S_NM_NACK, /* GSM 12.21 various NM_MT_*_NACK happened */
S_NM_IPACC_NACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_NACK happened */
S_NM_TEST_REP, /* GSM 12.21 Test Report */
};
/* SS_LCHAN signals */
@ -69,6 +78,12 @@ enum signal_lchan {
S_LCHAN_UNEXPECTED_RELEASE,
};
/* SS_SUBSCR signals */
enum signal_subscr {
S_SUBSCR_ATTACHED,
S_SUBSCR_DETACHED,
};
typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data);

View File

@ -3,8 +3,56 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/linuxlist.h>
#include <openbsc/gsm_04_11.h>
struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id);
/* One transaction */
struct gsm_trans {
/* Entry in list of all transactions */
struct llist_head entry;
/* The protocol within which we live */
u_int8_t protocol;
/* The current transaction ID */
u_int8_t transaction_id;
/* To whom we belong, unique identifier of remote MM entity */
struct gsm_subscriber *subscr;
/* The LCHAN that we're currently using to transmit messages */
struct gsm_lchan *lchan;
/* reference from MNCC or other application */
u_int32_t callref;
union {
struct {
/* current call state */
int state;
/* current timer and message queue */
int Tcurrent; /* current CC timer */
int T308_second; /* used to send release again */
struct timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
} cc;
struct {
int is_mt; /* is this a MO (0) or MT (1) transfer */
enum gsm411_cp_state cp_state;
enum gsm411_rp_state rp_state;
struct timer_list timer;
struct gsm_sms *sms;
} sms;
};
};
struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
u_int8_t proto, u_int8_t trans_id);
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
u_int32_t callref);

View File

@ -801,6 +801,10 @@ static int abis_nm_rcvmsg_report(struct msgb *mb)
rx_fail_evt_rep(mb);
dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
break;
case NM_MT_TEST_REP:
DEBUGPC(DNM, "Test Report\n");
dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
break;
default:
DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
break;
@ -1790,6 +1794,33 @@ int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0
return abis_nm_sendmsg(bts, msg);
}
/* Chapter 8.7.1 */
int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
u_int8_t test_nr, u_int8_t auton_report,
u_int8_t *phys_config, u_int16_t phys_config_len)
{
struct abis_om_hdr *oh;
struct msgb *msg = nm_msgb_alloc();
int len = 4; /* 2 TV attributes */
DEBUGP(DNM, "PEFORM TEST\n");
if (phys_config_len)
len += 3 + phys_config_len;
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
obj_class, bts_nr, trx_nr, ts_nr);
msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
if (phys_config_len)
msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
phys_config);
return abis_nm_sendmsg(bts, msg);
}
int abis_nm_event_reports(struct gsm_bts *bts, int on)
{
if (on == 0)

View File

@ -840,6 +840,27 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id)
return abis_rsl_sendmsg(msg);
}
/* Chapter 8.3.7 Request the release of multiframe mode of RLL connection.
This is what higher layers should call. The BTS then responds with
RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE,
which in turn is acknowledged by RSL CHANNEL RELEASE ACK, which calls
lchan_free() */
int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id)
{
struct msgb *msg = rsl_msgb_alloc();
struct abis_rsl_rll_hdr *rh;
rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
init_llm_hdr(rh, RSL_MT_REL_REQ);
//rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
rh->chan_nr = lchan2chan_nr(lchan);
rh->link_id = link_id;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
/* Chapter 8.4.2: Channel Activate Acknowledge */
static int rsl_rx_chan_act_ack(struct msgb *msg)
{
@ -1234,10 +1255,17 @@ static int abis_rsl_rx_rll(struct msgb *msg)
}
break;
case RSL_MT_REL_IND:
/* BTS informs us of having received DISC from MS */
DEBUGPC(DRLL, "RELEASE INDICATION\n");
/* we can now releae the channel on the BTS/Abis side */
rsl_chan_release(msg->lchan);
break;
case RSL_MT_REL_CONF:
/* BTS informs us of having received UA from MS,
* in response to DISC that we've sent earlier */
DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
/* we can now releae the channel on the BTS/Abis side */
rsl_chan_release(msg->lchan);
break;
case RSL_MT_ERROR_IND:
rc = rsl_rx_rll_err_ind(msg);

View File

@ -239,7 +239,7 @@ int lchan_auto_release(struct gsm_lchan *lchan)
}
DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr);
rsl_chan_release(lchan);
rsl_release_request(lchan, 0);
return 1;
}

View File

@ -22,6 +22,7 @@
#include <openbsc/gsm_data.h>
#include <openbsc/db.h>
#include <openbsc/talloc.h>
#include <libgen.h>
#include <stdio.h>
@ -74,13 +75,23 @@ static char *create_stmts[] = {
"UNIQUE (subscriber_id, equipment_id) "
")",
"CREATE TABLE IF NOT EXISTS SMS ("
/* metadata, not part of sms */
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"created TIMESTAMP NOT NULL, "
"sent TIMESTAMP, "
"sender_id NUMERIC NOT NULL, "
"receiver_id NUMERIC NOT NULL, "
"header NUMERIC, "
"text TEXT NOT NULL "
"sender_id INTEGER NOT NULL, "
"receiver_id INTEGER NOT NULL, "
/* data directly copied/derived from SMS */
"valid_until TIMESTAMP, "
"reply_path_req INTEGER NOT NULL, "
"status_rep_req INTEGER NOT NULL, "
"protocol_id INTEGER NOT NULL, "
"data_coding_scheme INTEGER NOT NULL, "
"dest_addr TEXT, "
"user_data BLOB, " /* TP-UD */
/* additional data, interpreted from SMS */
"header BLOB, " /* UD Header */
"text TEXT " /* decoded UD after UDH */
")",
"CREATE TABLE IF NOT EXISTS VLR ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
@ -235,6 +246,13 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
);
free(quoted);
break;
case GSM_SUBSCRIBER_ID:
dbi_conn_quote_string_copy(conn, id, &quoted);
result = dbi_conn_queryf(conn,
"SELECT * FROM Subscriber "
"WHERE id = %s ", quoted);
free(quoted);
break;
default:
printf("DB: Unknown query selector for Subscriber.\n");
return NULL;
@ -445,17 +463,31 @@ int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IM
int db_sms_store(struct gsm_sms *sms)
{
dbi_result result;
char *q_text;
char *q_text, *q_daddr;
unsigned char *q_udata;
char *validity_timestamp = "2222-2-2";
/* FIXME: generate validity timestamp based on validity_minutes */
dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
dbi_conn_quote_string_copy(conn, (char *)sms->dest_addr, &q_daddr);
dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
&q_udata);
/* FIXME: correct validity period */
result = dbi_conn_queryf(conn,
"INSERT INTO SMS "
"(created,sender_id,receiver_id,header,text) VALUES "
"(datetime('now'),%llu,%llu,%s,%s)",
"(created, sender_id, receiver_id, valid_until, "
"reply_path_req, status_rep_req, protocol_id, "
"data_coding_scheme, dest_addr, user_data, text) VALUES "
"(datetime('now'), %llu, %llu, %u, "
"%u, %u, %u, %u, %s, %s, %s)",
sms->sender->id,
sms->receiver ? sms->receiver->id : 0,
NULL, q_text);
sms->receiver ? sms->receiver->id : 0, validity_timestamp,
sms->reply_path_req, sms->status_rep_req, sms->protocol_id,
sms->data_coding_scheme, q_daddr, q_udata, q_text);
free(q_text);
free(q_daddr);
free(q_udata);
if (!result)
return -EIO;
@ -468,22 +500,63 @@ int db_sms_store(struct gsm_sms *sms)
struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id)
{
dbi_result result;
struct gsm_sms *sms = malloc(sizeof(*sms));
long long unsigned int sender_id, receiver_id;
struct gsm_sms *sms = sms_alloc();
const char *text, *daddr;
const unsigned char *user_data;
if (!sms) {
free(sms);
if (!sms)
return NULL;
}
result = dbi_conn_queryf(conn,
"SELECT * FROM SMS "
"WHERE id >= %llu ORDER BY id", min_id);
"WHERE id >= %llu AND sent is NULL ORDER BY id",
min_id);
if (!result) {
free(sms);
sms_free(sms);
return NULL;
}
if (!dbi_result_next_row(result)) {
printf("DB: Failed to find any SMS.\n");
dbi_result_free(result);
sms_free(sms);
return NULL;
}
sms->id = dbi_result_get_ulonglong(result, "id");
/* FIXME: fill gsm_sms from database */
sender_id = dbi_result_get_ulonglong(result, "sender_id");
sms->sender = subscr_get_by_id(net, sender_id);
receiver_id = dbi_result_get_ulonglong(result, "receiver_id");
sms->receiver = subscr_get_by_id(net, receiver_id);
/* FIXME: validity */
/* FIXME: those should all be get_uchar, but sqlite3 is braindead */
sms->reply_path_req = dbi_result_get_uint(result, "reply_path_req");
sms->status_rep_req = dbi_result_get_uint(result, "status_rep_req");
sms->ud_hdr_ind = dbi_result_get_uint(result, "ud_hdr_ind");
sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
sms->data_coding_scheme = dbi_result_get_uint(result,
"data_coding_scheme");
/* sms->msg_ref is temporary and not stored in DB */
daddr = dbi_result_get_string(result, "dest_addr");
if (daddr) {
strncpy(sms->dest_addr, daddr, sizeof(sms->dest_addr));
sms->dest_addr[sizeof(sms->dest_addr)-1] = '\0';
}
sms->user_data_len = dbi_result_get_field_length(result, "user_data");
user_data = dbi_result_get_binary(result, "user_data");
if (sms->user_data_len > sizeof(sms->user_data))
sms->user_data_len = sizeof(sms->user_data);
memcpy(sms->user_data, user_data, sms->user_data_len);
text = dbi_result_get_string(result, "text");
if (text) {
strncpy(sms->text, text, sizeof(sms->text));
sms->text[sizeof(sms->text)-1] = '\0';
}
dbi_result_free(result);
return sms;

View File

@ -245,7 +245,7 @@ static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
rep->flags |= MEAS_REP_F_BA1;
if (data[0] & 0x40)
rep->flags |= MEAS_REP_F_DTX;
if (data[1] & 0x40)
if ((data[1] & 0x40) == 0x00)
rep->flags |= MEAS_REP_F_VALID;
rep->rxlev_full = data[0] & 0x3f;
@ -1610,7 +1610,7 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
return -EINVAL;
}
DEBUGP(DRR, "<- Channel was requested by %s\n",
subscr->name ? subscr->name : subscr->imsi);
subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi);
subscr->equipment.classmark2_len = *classmark2_lv;
memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
@ -1783,6 +1783,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan)
/* Send actual release request to MS */
gsm48_sendmsg(msg, NULL);
/* FIXME: Start Timer T3109 */
/* Deactivate the SACCH on the BTS side */
return rsl_deact_sacch(lchan);
@ -3498,22 +3499,9 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
}
/* store setup informations until paging was successfull */
memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
/* start paging subscriber on all BTS with her location */
subscr->net = net;
bts = NULL;
do {
bts = gsm_bts_by_lac(net, subscr->lac, bts);
if (!bts)
break;
DEBUGP(DCC, "(bts %d trx - ts - ti -- sub %s) "
"Received '%s' from MNCC with "
"unallocated channel, paging.\n",
bts->nr, data->called.number,
get_mncc_name(msg_type));
/* Trigger paging */
paging_request(net, subscr, RSL_CHANNEED_TCH_F,
setup_trig_pag_evt, subscr);
} while (1);
/* Trigger paging */
paging_request(net, subscr, RSL_CHANNEED_TCH_F,
setup_trig_pag_evt, subscr);
return 0;
}
/* Assign lchan */
@ -3632,7 +3620,7 @@ static int gsm0408_rcv_cc(struct msgb *msg)
}
/* Find transaction */
trans = trans_find_by_id(lchan, transaction_id);
trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
"Received '%s' from MS in state %d (%s)\n",

View File

@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <netinet/in.h>
#include <openbsc/msgb.h>
@ -42,45 +43,99 @@
#include <openbsc/signal.h>
#include <openbsc/db.h>
#include <openbsc/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/paging.h>
#define GSM411_ALLOC_SIZE 1024
#define GSM411_ALLOC_HEADROOM 128
static void *tall_sms_ctx;
static void *tall_gsms_ctx;
static u_int32_t new_callref = 0x40000001;
struct gsm_sms *sms_alloc(void)
{
return talloc_zero(tall_gsms_ctx, struct gsm_sms);
}
void sms_free(struct gsm_sms *sms)
{
/* drop references to subscriber structure */
if (sms->sender)
subscr_put(sms->sender);
if (sms->receiver)
subscr_put(sms->receiver);
talloc_free(sms);
}
struct msgb *gsm411_msgb_alloc(void)
{
return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM,
"GSM 04.11");
}
int gsm0411_sendmsg(struct msgb *msg)
static int gsm411_sendmsg(struct msgb *msg)
{
if (msg->lchan)
msg->trx = msg->lchan->ts->trx;
msg->l3h = msg->data;
DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
return rsl_data_request(msg, 0);
}
#if 0
static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
/* Prefix msg with a 04.08/04.11 CP header */
static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
u_int8_t msg_type)
{
}
#endif
struct gsm48_hdr *gh;
static unsigned long gsm340_validity_period(struct sms_submit *sms)
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
/* Outgoing needs the highest bit set */
gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
gh->msg_type = msg_type;
/* assign the outgoing lchan */
msg->lchan = trans->lchan;
/* mobile originating */
switch (gh->msg_type) {
case GSM411_MT_CP_DATA:
/* 5.2.3.1.2: enter MO-wait for CP-ack */
trans->sms.cp_state = GSM411_CPS_WAIT_CP_ACK;
break;
}
return gsm411_sendmsg(msg);
}
/* Prefix msg with a RP-DATA header and send as CP-DATA */
static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans,
u_int8_t rp_msg_type, u_int8_t rp_msg_ref)
{
struct gsm411_rp_hdr *rp;
/* GSM 04.11 RP-DATA header */
rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
rp->len = msg->len;
rp->msg_type = rp_msg_type;
rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */
return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA);
}
static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
{
u_int8_t vp;
unsigned long minutes;
switch (sms->vpf) {
switch (sms_vpf) {
case GSM340_TP_VPF_RELATIVE:
/* Chapter 9.2.3.12.1 */
vp = *(sms->vp);
vp = *(sms_vp);
if (vp <= 143)
minutes = vp + 1 * 5;
else if (vp <= 167)
@ -139,57 +194,146 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
return alpha;
}
static int gsm340_rx_sms_submit(struct msgb *msg, struct sms_submit *sms,
struct gsm_sms *gsms)
static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
{
if (db_sms_store(gsms) != 0) {
DEBUGP(DSMS, "Failed to store SMS in Database\n");
talloc_free(sms);
talloc_free(gsms);
return -EIO;
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
/* dispatch a signal to tell higher level about it */
dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms);
return 0;
}
/* process an incoming TPDU (called from RP-DATA) */
/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */
static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
struct gsm_subscriber *subscr)
{
int len_in_bytes;
oa[1] = 0xb9; /* networks-specific number, private numbering plan */
len_in_bytes = encode_bcd_number(oa, oa_len, 1, subscr->extension);
/* GSM 03.40 tells us the length is in 'useful semi-octets' */
oa[0] = strlen(subscr->extension) & 0xff;
return len_in_bytes;
}
static u_int8_t bcdify(u_int8_t value)
{
u_int8_t ret;
ret = value / 10;
ret |= (value % 10) << 4;
return ret;
}
/* Generate 03.40 TP-SCTS */
static void gsm340_gen_scts(u_int8_t *scts, time_t time)
{
struct tm *tm = localtime(&time);
*scts++ = bcdify(tm->tm_year % 100);
*scts++ = bcdify(tm->tm_mon);
*scts++ = bcdify(tm->tm_mday);
*scts++ = bcdify(tm->tm_hour);
*scts++ = bcdify(tm->tm_min);
*scts++ = bcdify(tm->tm_sec);
*scts++ = 0; /* FIXME: timezone */
}
/* generate a msgb containing a TPDU derived from struct gsm_sms,
* returns total size of TPDU */
static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
{
u_int8_t *smsp;
u_int8_t oa[12]; /* max len per 03.40 */
u_int8_t oa_len = 0;
unsigned int old_msg_len = msg->len;
/* generate first octet with masked bits */
smsp = msgb_put(msg, 1);
/* TP-MTI (message type indicator) */
*smsp = GSM340_SMS_DELIVER_SC2MS;
/* TP-MMS (more messages to send) */
if (0 /* FIXME */)
*smsp |= 0x04;
/* TP-SRI(deliver)/SRR(submit) */
if (sms->status_rep_req)
*smsp |= 0x20;
/* TP-UDHI (indicating TP-UD contains a header) */
if (sms->ud_hdr_ind)
*smsp |= 0x40;
#if 0
/* TP-RP (indicating that a reply path exists) */
if (sms->
*smsp |= 0x80;
#endif
/* generate originator address */
oa_len = gsm340_gen_oa(oa, sizeof(oa), sms->sender);
smsp = msgb_put(msg, oa_len);
memcpy(smsp, oa, oa_len);
/* generate TP-PID */
smsp = msgb_put(msg, 1);
*smsp = sms->protocol_id;
/* generate TP-DCS */
smsp = msgb_put(msg, 1);
*smsp = sms->data_coding_scheme;
/* generate TP-SCTS */
smsp = msgb_put(msg, 7);
gsm340_gen_scts(smsp, time(NULL));
/* generate TP-UDL */
smsp = msgb_put(msg, 1);
*smsp = sms->user_data_len;
/* generate TP-UD */
smsp = msgb_put(msg, sms->user_data_len);
memcpy(smsp, sms->user_data, sms->user_data_len);
return msg->len - old_msg_len;
}
/* process an incoming TPDU (called from RP-DATA)
* return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
static int gsm340_rx_tpdu(struct msgb *msg)
{
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
u_int8_t *smsp = msgb_sms(msg);
struct sms_submit *sms;
struct gsm_sms *gsms;
u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
u_int8_t *sms_vp;
u_int8_t da_len_bytes;
u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
sms = talloc(tall_sms_ctx, struct sms_submit);
if (!sms)
return -ENOMEM;
memset(sms, 0, sizeof(*sms));
gsms = talloc(tall_gsms_ctx, struct gsm_sms);
if (!gsms) {
talloc_free(sms);
return -ENOMEM;
}
memset(gsms, 0, sizeof(*gsms));
gsms = sms_alloc();
if (!gsms)
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
/* invert those fields where 0 means active/present */
sms->mti = *smsp & 0x03;
sms->mms = !!(*smsp & 0x04);
sms->vpf = (*smsp & 0x18) >> 3;
sms->sri = !!(*smsp & 0x20);
sms->udhi= !!(*smsp & 0x40);
sms->rp = !!(*smsp & 0x80);
sms_mti = *smsp & 0x03;
sms_mms = !!(*smsp & 0x04);
sms_vpf = (*smsp & 0x18) >> 3;
gsms->status_rep_req = (*smsp & 0x20);
gsms->ud_hdr_ind = (*smsp & 0x40);
sms_rp = (*smsp & 0x80);
smsp++;
sms->msg_ref = *smsp++;
gsms->msg_ref = *smsp++;
/* length in bytes of the destination address */
da_len_bytes = 2 + *smsp/2 + *smsp%2;
if (da_len_bytes > 12) {
DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
rc = -EIO;
rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
goto out;
}
memset(address_lv, 0, sizeof(address_lv));
@ -197,145 +341,117 @@ static int gsm340_rx_tpdu(struct msgb *msg)
/* mangle first byte to reflect length in bytes, not digits */
address_lv[0] = da_len_bytes - 1;
/* convert to real number */
decode_bcd_number(sms->dest_addr, sizeof(sms->dest_addr), address_lv, 1);
decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
smsp += da_len_bytes;
sms->pid = *smsp++;
gsms->protocol_id = *smsp++;
gsms->data_coding_scheme = *smsp++;
sms->dcs = *smsp++;
sms->alphabet = gsm338_get_sms_alphabet(sms->dcs);
sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
switch (sms->vpf) {
switch (sms_vpf) {
case GSM340_TP_VPF_RELATIVE:
sms->vp = smsp++;
sms_vp = smsp++;
break;
case GSM340_TP_VPF_ABSOLUTE:
case GSM340_TP_VPF_ENHANCED:
sms->vp = smsp;
sms_vp = smsp;
smsp += 7;
break;
default:
DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
sms->vpf);
sms_vpf);
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
sms->ud_len = *smsp++;
if (sms->ud_len)
sms->user_data = smsp;
else
sms->user_data = NULL;
gsms->user_data_len = *smsp++;
if (gsms->user_data_len) {
memcpy(gsms->user_data, smsp, gsms->user_data_len);
if (sms->ud_len) {
switch (sms->alphabet) {
switch (sms_alphabet) {
case DCS_7BIT_DEFAULT:
gsm_7bit_decode(sms->decoded, smsp, sms->ud_len);
gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
break;
case DCS_8BIT_DATA:
case DCS_UCS2:
case DCS_NONE:
memcpy(sms->decoded, sms->user_data, sms->ud_len);
break;
}
}
DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
"PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
"UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded : hexdump(sms->user_data, sms->ud_len));
"UserData: \"%s\"\n", sms_mti, sms_vpf, gsms->msg_ref,
gsms->protocol_id, gsms->data_coding_scheme,
gsms->dest_addr, gsms->user_data_len,
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
hexdump(gsms->user_data, gsms->user_data_len));
dispatch_signal(SS_SMS, 0, sms);
gsms->sender = subscr_get(msg->lchan->subscr);
gsms->sender = msg->lchan->subscr;
/* FIXME: sender refcount */
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
dispatch_signal(SS_SMS, 0, gsms);
/* determine gsms->receiver based on dialled number */
gsms->receiver = subscr_get_by_extension(bts->network, sms->dest_addr);
gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
if (!gsms->receiver) {
rc = 1; /* cause 1: unknown subscriber */
goto out;
}
if (sms->user_data)
strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
switch (sms->mti) {
switch (sms_mti) {
case GSM340_SMS_SUBMIT_MS2SC:
/* MS is submitting a SMS */
rc = gsm340_rx_sms_submit(msg, sms, gsms);
rc = gsm340_rx_sms_submit(msg, gsms);
break;
case GSM340_SMS_COMMAND_MS2SC:
case GSM340_SMS_DELIVER_REP_MS2SC:
DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
default:
DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
}
if (!rc && !gsms->receiver)
rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
out:
talloc_free(gsms);
talloc_free(sms);
sms_free(gsms);
return rc;
}
static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
u_int8_t msg_ref)
static int gsm411_send_rp_ack(struct gsm_trans *trans, u_int8_t msg_ref)
{
struct msgb *msg = gsm411_msgb_alloc();
struct gsm48_hdr *gh;
struct gsm411_rp_hdr *rp;
msg->lchan = lchan;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
// Outgoing needs the highest bit set
gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
gh->msg_type = GSM411_MT_CP_DATA;
rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
rp->len = 2;
rp->msg_type = GSM411_MT_RP_ACK_MT;
rp->msg_ref = msg_ref;
DEBUGP(DSMS, "TX: SMS RP ACK\n");
return gsm0411_sendmsg(msg);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ACK_MT, msg_ref);
}
static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
u_int8_t msg_ref, u_int8_t cause)
static int gsm411_send_rp_error(struct gsm_trans *trans,
u_int8_t msg_ref, u_int8_t cause)
{
struct msgb *msg = gsm411_msgb_alloc();
struct gsm48_hdr *gh;
struct gsm411_rp_hdr *rp;
msg->lchan = lchan;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
// Outgoing needs the highest bit set
gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
gh->msg_type = GSM411_MT_CP_DATA;
rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
rp->msg_type = GSM411_MT_RP_ERROR_MT;
rp->msg_ref = msg_ref;
msgb_tv_put(msg, 1, cause);
DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
return gsm0411_sendmsg(msg);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
}
/* Receive a 04.11 TPDU inside RP-DATA / user data */
static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm411_rp_hdr *rph,
static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph,
u_int8_t src_len, u_int8_t *src,
u_int8_t dst_len, u_int8_t *dst,
u_int8_t tpdu_len, u_int8_t *tpdu)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t trans_id = gh->proto_discr >> 4;
int rc = 0;
if (src_len && src)
@ -343,24 +459,26 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm411_rp_hdr *rph,
if (!dst_len || !dst || !tpdu_len || !tpdu) {
DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_INV_MAND_INF);
return -EIO;
}
msg->smsh = tpdu;
DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
//return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
rc = gsm340_rx_tpdu(msg);
if (rc == 0)
return gsm411_send_rp_ack(msg->lchan, trans_id, rph->msg_ref);
return gsm411_send_rp_ack(trans, rph->msg_ref);
else if (rc > 0)
return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
return gsm411_send_rp_error(trans, rph->msg_ref, rc);
else
return rc;
}
/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
static int gsm411_rx_rp_data(struct msgb *msg, struct gsm411_rp_hdr *rph)
static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
u_int8_t src_len, dst_len, rpud_len;
u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
@ -378,12 +496,91 @@ static int gsm411_rx_rp_data(struct msgb *msg, struct gsm411_rp_hdr *rph)
if (rpud_len)
rp_ud = &rph->data[1+src_len+1+dst_len+1];
DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n", src_len, dst_len, rpud_len);
return gsm411_rx_rp_ud(msg, rph, src_len, src, dst_len, dst,
DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
src_len, dst_len, rpud_len);
return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
rpud_len, rp_ud);
}
static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
struct gsm_sms *sms = trans->sms.sms;
/* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
* successfully received a SMS. We can now safely mark it as
* transmitted */
/* we need to look-up the transaction based on rph->msg_ref to
* identify which particular RP_DATA/SMS-submit was ACKed */
if (!sms) {
DEBUGP(DSMS, "RX RP-ACK (MT) but no sms in transaction?!?\n");
put_lchan(trans->lchan);
return -EIO;
}
/* mark this SMS as sent in database */
db_sms_mark_sent(sms);
dispatch_signal(SS_SMS, S_SMS_DELIVERED, sms);
sms_free(sms);
trans->sms.sms = NULL;
put_lchan(trans->lchan);
return 0;
}
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
struct gsm_sms *sms = trans->sms.sms;
u_int8_t cause_len = rph->data[0];
u_int8_t cause = rph->data[1];
/* Error in response to MT RP_DATA, i.e. the MS did not
* successfully receive the SMS. We need to investigate
* the cause and take action depending on it */
DEBUGP(DSMS, "RX SMS RP-ERROR Cause=0x%02x\n", cause);
/* we need to look-up the transaction based on rph->msg_ref to
* identify which particular RP_DATA/SMS-submit failed */
if (!sms) {
DEBUGP(DSMS, "RX RP-ERR (MT) but no sms in transaction?!?\n");
put_lchan(trans->lchan);
return -EIO;
}
sms_free(sms);
trans->sms.sms = NULL;
put_lchan(trans->lchan);
return 0;
}
static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
int rc;
/* MS tells us that it has memory for more SMS, we need
* to check if we have any pending messages for it and then
* transfer those */
dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
rc = gsm411_send_rp_ack(trans, rph->msg_ref);
trans->sms.rp_state = GSM411_RPS_IDLE;
return rc;
}
static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
struct gsm_trans *trans)
{
struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
u_int8_t msg_type = rp_data->msg_type & 0x07;
@ -391,65 +588,133 @@ static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
switch (msg_type) {
case GSM411_MT_RP_DATA_MO:
DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
rc = gsm411_rx_rp_data(msg, rp_data);
DEBUGP(DSMS, "RX SMS RP-DATA (MO)\n");
/* start TR2N and enter 'wait to send RP-ACK state' */
trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
rc = gsm411_rx_rp_data(msg, trans, rp_data);
break;
case GSM411_MT_RP_ACK_MO:
/* Acnkowledgement to MT RP_DATA */
case GSM411_MT_RP_ERROR_MO:
/* Error in response to MT RP_DATA */
DEBUGP(DSMS,"RX SMS RP-ACK (MO)\n");
rc = gsm411_rx_rp_ack(msg, trans, rp_data);
break;
case GSM411_MT_RP_SMMA_MO:
/* MS tells us that it has memory for more SMS, we need
* to check if we have any pending messages for it and then
* transfer those */
DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
DEBUGP(DSMS, "RX SMS RP-SMMA\n");
/* start TR2N and enter 'wait to send RP-ACK state' */
trans->sms.rp_state = GSM411_RPS_WAIT_TO_TX_RP_ACK;
rc = gsm411_rx_rp_smma(msg, trans, rp_data);
break;
case GSM411_MT_RP_ERROR_MO:
rc = gsm411_rx_rp_error(msg, trans, rp_data);
break;
default:
DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
break;
}
return rc;
}
/* send CP-ACK to given transaction */
static int gsm411_tx_cp_ack(struct gsm_trans *trans)
{
struct msgb *msg = gsm411_msgb_alloc();
return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ACK);
}
static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
{
struct msgb *msg = gsm411_msgb_alloc();
u_int8_t *causep;
causep = msgb_put(msg, 1);
*causep = cause;
return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_ERROR);
}
/* Entry point for incoming GSM48_PDISC_SMS from abis_rsl.c */
int gsm0411_rcv_sms(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t msg_type = gh->msg_type;
u_int8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
struct gsm_lchan *lchan = msg->lchan;
struct gsm_trans *trans;
int rc = 0;
if (!lchan->subscr)
return -EIO;
/* FIXME: send some error message */
trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
transaction_id);
if (!trans) {
DEBUGP(DSMS, "Unknown transaction ID %x, "
"creating new trans\n", transaction_id);
trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
DEBUGP(DSMS, "No memory for trans\n");
/* FIXME: send some error message */
return -ENOMEM;
}
trans->sms.cp_state = GSM411_CPS_IDLE;
trans->sms.rp_state = GSM411_RPS_IDLE;
trans->sms.is_mt = 0;
trans->lchan = lchan;
use_lchan(lchan);
}
switch(msg_type) {
case GSM411_MT_CP_DATA:
DEBUGP(DSMS, "SMS CP-DATA\n");
rc = gsm411_rx_cp_data(msg, gh);
DEBUGP(DSMS, "RX SMS CP-DATA\n");
if (!trans->sms.is_mt) {
/* 5.2.3.1.3: MO state exists when SMC has received
* CP-DATA, including sending of the assoc. CP-ACK */
trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
}
rc = gsm411_rx_cp_data(msg, gh, trans);
/* Send CP-ACK or CP-ERORR in response */
if (rc < 0) {
rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_NET_FAIL);
} else
rc = gsm411_tx_cp_ack(trans);
break;
case GSM411_MT_CP_ACK:
DEBUGP(DSMS, "SMS CP-ACK\n");
/* previous CP-DATA in this transaction was confirmed */
DEBUGP(DSMS, "RX SMS CP-ACK\n");
if (!trans->sms.is_mt) {
/* 5.2.3.1.3: MO state exists when SMC has received
* CP-ACK */
trans->sms.cp_state = GSM411_CPS_MM_ESTABLISHED;
/* FIXME: we have sont one CP-DATA, which was now
* acknowledged. Check if we want to transfer more,
* i.e. multi-part message */
trans->sms.cp_state = GSM411_CPS_IDLE;
trans_free(trans);
}
break;
case GSM411_MT_CP_ERROR:
DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
DEBUGP(DSMS, "RX SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
trans->sms.cp_state = GSM411_CPS_IDLE;
trans_free(trans);
break;
default:
DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
DEBUGP(DSMS, "RX Unimplemented CP msg_type: 0x%02x\n", msg_type);
rc = gsm411_tx_cp_error(trans, GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
trans_free(trans);
break;
}
return rc;
}
/* Test TPDU - 25c3 welcome */
#if 0
static u_int8_t tpdu_test[] = {
0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
};
#else
/* Test TPDU - ALL YOUR */
static u_int8_t tpdu_test[] = {
0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
@ -459,55 +724,127 @@ static u_int8_t tpdu_test[] = {
};
#endif
int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
/* Take a SMS in gsm_sms structure and send it through lchan */
int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
{
struct msgb *msg = gsm411_msgb_alloc();
struct gsm48_hdr *gh;
struct gsm411_rp_hdr *rp;
u_int8_t *data;
struct gsm_trans *trans;
u_int8_t *data, *rp_ud_len;
u_int8_t msg_ref = 42;
u_int8_t transaction_id = 1; /* FIXME: random */
int rc;
msg->lchan = lchan;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_SMS;
gh->msg_type = GSM411_MT_CP_DATA;
DEBUGP(DSMS, "send_sms_lchan()\n");
rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
rp->len = sizeof(tpdu_test) + 10;
rp->msg_type = GSM411_MT_RP_DATA_MT;
rp->msg_ref = 42; /* FIXME: Choose randomly */
/* Hardcode OA for now */
/* FIXME: allocate transaction with message reference */
trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
DEBUGP(DSMS, "No memory for trans\n");
/* FIXME: send some error message */
return -ENOMEM;
}
trans->sms.cp_state = GSM411_CPS_IDLE;
trans->sms.rp_state = GSM411_RPS_IDLE;
trans->sms.is_mt = 1;
trans->sms.sms = sms;
trans->lchan = lchan;
use_lchan(lchan);
/* Hardcode SMSC Originating Address for now */
data = (u_int8_t *)msgb_put(msg, 8);
data[0] = 0x07;
data[1] = 0x91;
data[2] = 0x44;
data[0] = 0x07; /* originator length == 7 */
data[1] = 0x91; /* type of number: international, ISDN */
data[2] = 0x44; /* 447785016005 */
data[3] = 0x77;
data[4] = 0x58;
data[5] = 0x10;
data[6] = 0x06;
data[7] = 0x50;
/* Hardcoded Destination Address */
data = (u_int8_t *)msgb_put(msg, 1);
data[0] = 0;
data[0] = 0; /* destination length == 0 */
/* FIXME: Hardcoded for now */
//smslen = gsm0411_tpdu_from_sms(tpdu, sms);
/* obtain a pointer for the rp_ud_len, so we can fill it later */
rp_ud_len = (u_int8_t *)msgb_put(msg, 1);
/* RPDU length */
data = (u_int8_t *)msgb_put(msg, 1);
data[0] = sizeof(tpdu_test);
#if 1
/* generate the 03.40 TPDU */
rc = gsm340_gen_tpdu(msg, sms);
if (rc < 0) {
msgb_free(msg);
return rc;
}
data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
//memcpy(data, tpdu, smslen);
*rp_ud_len = rc;
#else
data = msgb_put(msg, sizeof(tpdu_test));
memcpy(data, tpdu_test, sizeof(tpdu_test));
*rp_ud_len = sizeof(tpdu_test);
#endif
DEBUGP(DSMS, "TX: SMS SUBMIT\n");
DEBUGP(DSMS, "TX: SMS DELIVER\n");
return gsm0411_sendmsg(msg);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */
}
/* paging callback */
static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *_lchan, void *_sms)
{
struct gsm_lchan *lchan = _lchan;
struct gsm_sms *sms = _sms;
int rc;
DEBUGP(DSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
"lchan=%p, sms=%p)\n", hooknum, event, msg, lchan, sms);
if (hooknum != GSM_HOOK_RR_PAGING)
return -EINVAL;
switch (event) {
case GSM_PAGING_SUCCEEDED:
/* Paging aborted without lchan ?!? */
if (!lchan) {
sms_free(sms);
rc = -EIO;
break;
}
rc = gsm411_send_sms_lchan(lchan, sms);
break;
case GSM_PAGING_EXPIRED:
sms_free(sms);
rc = -ETIMEDOUT;
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
struct gsm_sms *sms)
{
/* check if we already have an open lchan to the subscriber.
* if yes, send the SMS this way */
//if (subscr->lchan)
//return gsm411_send_sms_lchan(subscr->lchan, sms);
/* if not, we have to start paging */
paging_request(subscr->net, subscr, RSL_CHANNEED_SDCCH,
paging_cb_send_sms, sms);
return 0;
}
static __attribute__((constructor)) void on_dso_load_sms(void)
{
tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms_submit");
tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms");
}

View File

@ -234,7 +234,7 @@ static const char *bts_types[] = {
[GSM_BTS_TYPE_NANOBTS_1800] = "nanobts1800",
};
enum gsm_bts_type parse_btstype(char *arg)
enum gsm_bts_type parse_btstype(const char *arg)
{
int i;
for (i = 0; i < ARRAY_SIZE(bts_types); i++) {

View File

@ -32,6 +32,7 @@
#include <openbsc/paging.h>
#include <openbsc/debug.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/db.h>
LLIST_HEAD(active_subscribers);
@ -162,6 +163,22 @@ struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
return db_get_subscriber(net, GSM_SUBSCRIBER_EXTENSION, ext);
}
struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
unsigned long long id)
{
struct gsm_subscriber *subscr;
char buf[32];
sprintf(buf, "%llu", id);
llist_for_each_entry(subscr, &active_subscribers, entry) {
if (subscr->id == id)
return subscr_get(subscr);
}
return db_get_subscriber(net, GSM_SUBSCRIBER_ID, buf);
}
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
{
/* FIXME: Migrate pending requests from one BSC to another */
@ -170,12 +187,13 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
s->net = bts->network;
/* Indicate "attached to LAC" */
s->lac = bts->location_area_code;
dispatch_signal(SS_SUBSCR, S_SUBSCR_ATTACHED, s);
break;
case GSM_SUBSCRIBER_UPDATE_DETACHED:
/* Only detach if we are currently in this area */
if (bts->location_area_code == s->lac)
s->lac = 0;
dispatch_signal(SS_SUBSCR, S_SUBSCR_DETACHED, s);
break;
default:
fprintf(stderr, "subscr_update with unknown reason: %d\n",

View File

@ -38,9 +38,11 @@
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
static struct gsm_network *gsmnet;
static int net_listen;
static int restart;
static char *prim_oml_ip;
static char *unit_id;
@ -66,12 +68,61 @@ static int ipacc_msg_nack(int mt)
return 0;
}
struct ipacc_ferr_elem {
int16_t freq_err;
u_int8_t freq_qual;
u_int8_t arfcn;
} __attribute__((packed));
static int test_rep(void *_msg)
{
struct msgb *msg = _msg;
struct abis_om_fom_hdr *foh = msgb_l3(msg);
u_int16_t test_rep_len, ferr_list_len;
struct ipacc_ferr_elem *ife;
int i;
DEBUGP(DNM, "TEST REPORT: ");
if (foh->data[0] != NM_ATT_TEST_NO ||
foh->data[2] != NM_ATT_TEST_REPORT)
return -EINVAL;
DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
/* data[2] == NM_ATT_TEST_REPORT */
/* data[3..4]: test_rep_len */
test_rep_len = ntohs(*(u_int16_t *) &foh->data[3]);
/* data[5]: ip.access test result */
DEBUGPC(DNM, "test_res=%u\n", foh->data[5]);
/* data[6]: ip.access nested IE. 3 == freq_err_list */
switch (foh->data[6]) {
case 3:
/* data[7..8]: length of ferr_list */
ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
/* data[9...]: frequency error list elements */
for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
ife->arfcn, ntohs(ife->freq_err));
}
break;
default:
break;
}
return 0;
}
static int nm_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
switch (signal) {
case S_NM_IPACC_NACK:
return ipacc_msg_nack((int)signal_data);
case S_NM_TEST_REP:
return test_rep(signal_data);
default:
break;
}
@ -141,6 +192,9 @@ static void bootstrap_om(struct gsm_bts *bts)
printf("restarting BTS\n");
abis_nm_ipaccess_restart(bts);
}
if (net_listen) {
}
}
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
@ -170,6 +224,16 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
{
if (evt == EVT_STATECHG_OPER &&
obj_class == NM_OC_RADIO_CARRIER &&
new_state->availability == 3 &&
net_listen) {
struct gsm_bts_trx *trx = obj;
u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
NM_IPACC_TESTNO_FREQ_SYNC, 1,
phys_config, sizeof(phys_config));
}
return 0;
}
@ -183,7 +247,8 @@ static void print_help(void)
printf(" -u --unit-id UNIT_ID\n");
printf(" -o --oml-ip ip\n");
printf(" -r --restart\n");
printf(" -n flags/mask Set NVRAM attributes.\n");
printf(" -n flags/mask\tSet NVRAM attributes.\n");
printf(" -l --listen\tPerform Frequency Error test\n");
printf(" -h --help this text\n");
}
@ -205,9 +270,10 @@ int main(int argc, char **argv)
{ "oml-ip", 1, 0, 'o' },
{ "restart", 0, 0, 'r' },
{ "help", 0, 0, 'h' },
{ "listen", 0, 0, 'l' },
};
c = getopt_long(argc, argv, "u:o:rn:h", long_options,
c = getopt_long(argc, argv, "u:o:rn:lh", long_options,
&option_index);
if (c == -1)
@ -232,6 +298,9 @@ int main(int argc, char **argv)
ul = strtoul(slash+1, NULL, 16);
nv_mask = ul & 0xffff;
break;
case 'l':
net_listen = 1;
break;
case 'h':
print_usage();
print_help();

View File

@ -33,7 +33,7 @@ static const char *ipac_idtag_name(int tag)
return idtag_names[tag];
}
static int udp_sock(char *local_ip)
static int udp_sock(const char *ifname)
{
int fd, rc, bc = 1;
struct sockaddr_in sa;
@ -42,10 +42,16 @@ static int udp_sock(char *local_ip)
if (fd < 0)
return fd;
if (ifname) {
rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
strlen(ifname));
if (rc < 0)
goto err;
}
sa.sin_family = AF_INET;
sa.sin_port = htons(3006);
sa.sin_addr.s_addr = INADDR_ANY;
inet_aton(local_ip, &sa.sin_addr);
rc = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
if (rc < 0)
@ -56,6 +62,12 @@ static int udp_sock(char *local_ip)
goto err;
#if 0
/* we cannot bind, since the response packets don't come from
* the broadcast address */
sa.sin_family = AF_INET;
sa.sin_port = htons(3006);
inet_aton("255.255.255.255", &sa.sin_addr);
rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
if (rc < 0)
goto err;
@ -121,6 +133,13 @@ static int read_response(int fd)
if (len < 0)
return len;
/* 2 bytes length, 1 byte protocol (0xfe) */
if (buf[2] != 0xfe)
return 0;
if (buf[4] != IPAC_MSGT_ID_RESP)
return 0;
return parse_response(buf+6, len-6);
}
@ -149,21 +168,21 @@ static void timer_cb(void *_data)
int main(int argc, char **argv)
{
struct bsc_fd bfd;
char *local_ip;
char *ifname;
int rc;
printf("ipaccess-find (C) 2009 by Harald Welte\n");
printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
if (argc < 2) {
fprintf(stderr, "please specify the _local_ IP address as argument\n");
exit(2);
fprintf(stdout, "you might need to specify the outgoing\n"
" network interface, e.g. ``%s eth0''\n", argv[0]);
}
local_ip = argv[1];
ifname = argv[1];
bfd.cb = bfd_cb;
bfd.when = BSC_FD_READ | BSC_FD_WRITE;
bfd.fd = udp_sock(local_ip);
bfd.fd = udp_sock(ifname);
if (bfd.fd < 0) {
perror("Cannot create local socket for broadcast udp");
exit(1);

View File

@ -224,7 +224,8 @@ static void _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
return;
}
DEBUGP(DPAG, "Start paging on bts %d.\n", bts->nr);
DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n",
subscr->id, bts->nr);
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
req->subscr = subscr_get(subscr);
req->bts = bts;
@ -245,13 +246,14 @@ void paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
{
struct gsm_bts *bts = NULL;
/* start paging subscriber on all BTS within Location Area */
do {
bts = gsm_bts_by_lac(network, subscr->lac, bts);
if (!bts)
break;
/* Trigger paging */
_paging_request(bts, subscr, RSL_CHANNEED_TCH_F, cbfn, data);
_paging_request(bts, subscr, type, cbfn, data);
} while (1);
}

View File

@ -31,13 +31,16 @@
static void *tall_trans_ctx;
struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id)
struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
u_int8_t proto, u_int8_t trans_id)
{
struct gsm_trans *trans;
struct gsm_network *net = lchan->ts->trx->bts->network;
struct gsm_network *net = subscr->net;
llist_for_each_entry(trans, &net->trans_list, entry) {
if (trans->lchan == lchan && trans->transaction_id == trans_id)
if (trans->subscr == subscr &&
trans->protocol == proto &&
trans->transaction_id == trans_id)
return trans;
}
return NULL;

View File

@ -1034,6 +1034,52 @@ DEFUN(show_subscr,
return CMD_SUCCESS;
}
DEFUN(sms_send_pend,
sms_send_pend_cmd,
"sms send pending MIN_ID",
"Send all pending SMS starting from MIN_ID")
{
struct gsm_sms *sms;
sms = db_sms_get_unsent(gsmnet, atoi(argv[0]));
if (!sms)
return CMD_WARNING;
if (!sms->receiver) {
sms_free(sms);
return CMD_WARNING;
}
gsm411_send_sms_subscr(sms->receiver, sms);
return CMD_SUCCESS;
}
DEFUN(sms_send_ext,
sms_send_ext_cmd,
"sms send extension EXTEN .LINE",
"Send a message to a subscriber identified by EXTEN")
{
struct gsm_sms *sms;
//gsm411_send_sms_subscr(sms->receiver, sms);
return CMD_SUCCESS;
}
DEFUN(sms_send_imsi,
sms_send_imsi_cmd,
"sms send imsi IMSI .LINE",
"Send a message to a subscriber identified by IMSI")
{
struct gsm_sms *sms;
//gsm411_send_sms_subscr(sms->receiver, sms);
return CMD_SUCCESS;
}
DEFUN(cfg_subscr_name,
cfg_subscr_name_cmd,
"name NAME",
@ -1103,6 +1149,12 @@ int bsc_vty_init(struct gsm_network *net)
install_element(VIEW_NODE, &show_subscr_cmd);
install_element(VIEW_NODE, &sms_send_pend_cmd);
#if 0
install_element(VIEW_NODE, &sms_send_ext_cmd);
install_element(VIEW_NODE, &sms_send_imsi_cmd);
#endif
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
install_default(GSMNET_NODE);