Merge branch 'master' into config_file
Conflicts: openbsc/src/vty_interface.c
This commit is contained in:
commit
3c5cb256c2
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
105
openbsc/src/db.c
105
openbsc/src/db.c
|
@ -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, "ed);
|
||||
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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue