diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 3dc553144..d8cd9fa78 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -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); diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 201c77fbc..02bc52130 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -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); diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h index 12c607f54..c59df41cc 100644 --- a/openbsc/include/openbsc/gsm_04_11.h +++ b/openbsc/include/openbsc/gsm_04_11.h @@ -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 diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 7c8cf7cac..663c8698b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -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); diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 00eeb3287..3efb20c03 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -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, diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 2ce812d10..dea634462 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -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); diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 1450dbca5..5678c83e7 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -3,8 +3,56 @@ #include #include +#include +#include -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); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 0eb8657db..31f1df009 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -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) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1a2c58b16..726ef23a6 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -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); diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index e3d6ae67e..a66f70e8c 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -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; } diff --git a/openbsc/src/db.c b/openbsc/src/db.c index fc2950a36..7bb3c31ec 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -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; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 078e95f3b..b753e0d8d 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -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", diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 9218783ff..20555101a 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -42,45 +43,99 @@ #include #include #include +#include +#include #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"); } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 0ed08454a..370c41097 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -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++) { diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c index 748015693..d91298ee6 100644 --- a/openbsc/src/gsm_subscriber.c +++ b/openbsc/src/gsm_subscriber.c @@ -32,6 +32,7 @@ #include #include #include +#include #include 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", diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 5ccbaa70c..a7fb9c43b 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -38,9 +38,11 @@ #include #include #include +#include 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(); diff --git a/openbsc/src/ipaccess-find.c b/openbsc/src/ipaccess-find.c index db78922b9..f469b6788 100644 --- a/openbsc/src/ipaccess-find.c +++ b/openbsc/src/ipaccess-find.c @@ -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); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index b63a717b0..dd2215005 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -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); } diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index f4cef28d2..9e7c7948f 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -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; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 7213edfa8..45b2c7469 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -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);