diff --git a/hlrsync/hlrsync.py b/hlrsync/hlrsync.py new file mode 100755 index 000000000..b2a632b6f --- /dev/null +++ b/hlrsync/hlrsync.py @@ -0,0 +1,103 @@ +#!/usr/bin/python2.5 + +from __future__ import with_statement + +from pysqlite2 import dbapi2 as sqlite3 +import sys + +hlr = sqlite3.connect(sys.argv[1]) +web = sqlite3.connect(sys.argv[2]) + +# switch to autocommit +hlr.isolation_level = None +web.isolation_level = None + +hlr.row_factory = sqlite3.Row +web.row_factory = sqlite3.Row + +with hlr: + hlr_subscrs = hlr.execute(""" + SELECT * FROM Subscriber + """).fetchall() + hlr_tokens = hlr.execute(""" + SELECT * FROM AuthToken + """).fetchall() + +with web: + web_tokens = web.execute(""" + SELECT * FROM reg_tokens + """).fetchall() + +# index by subscr id +hlr_subscrs_by_id = {} +hlr_tokens_by_subscr_id = {} +for x in hlr_subscrs: + hlr_subscrs_by_id[x['id']] = x +del hlr_subscrs +for x in hlr_tokens: + hlr_tokens_by_subscr_id[x['subscriber_id']] = x +del hlr_tokens + +web_tokens_by_subscr_id = {} +for x in web_tokens: + web_tokens_by_subscr_id[x['subscriber_id']] = x +del web_tokens + +# remove leftover web_tokens and correct inconsistent fields +with web: + for x in web_tokens_by_subscr_id.values(): + subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) + if subscr is None: + web.execute(""" + DELETE FROM reg_tokens WHERE subscriber_id = ? + """, (x['subscriber_id'],)) + del web_tokens_by_subscr_id[x['subscriber_id']] + continue + if str(x['imsi']) != str(subscr['imsi']) or \ + x['extension'] != subscr['extension'] or \ + x['tmsi'] != subscr['tmsi'] or \ + x['lac'] != subscr['lac']: + web.execute(""" + UPDATE reg_tokens + SET imsi = ?, extension = ?, tmsi = ?, lac = ? + WHERE subscriber_id = ? + """, (str(subscr['imsi']), subscr['extension'], x['subscriber_id'])) + x['imsi'] = str(subscr['imsi']) + x['extension'] = subscr['extension'] + x['tmsi'] = subscr['tmsi'] + x['lac'] = subscr['lac'] + +# add missing web_tokens +with web: + for x in hlr_tokens_by_subscr_id.values(): + subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) + if subscr is None: + hlr.execute(""" + DELETE FROM AuthToken WHERE subscriber_id = ? + """, (x['subscriber_id'],)) + del hlr_tokens_by_subscr_id[x['subscriber_id']] + continue + webtoken = web_tokens_by_subscr_id.get(x['subscriber_id'], None) + if webtoken is None: + web.execute(""" + INSERT INTO reg_tokens + (subscriber_id, extension, reg_completed, name, email, lac, imsi, token, tmsi) + VALUES + (?, ?, 0, ?, '', ?, ?, ?, ?) + """, (x['subscriber_id'], subscr['extension'], subscr['name'], + subscr['lac'], str(subscr['imsi']), x['token'], subscr['tmsi'])) + +# authorize subscribers +with hlr: + for x in web_tokens_by_subscr_id.values(): + subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) + if x['reg_completed'] and not subscr['authorized']: + hlr.execute(""" + UPDATE Subscriber + SET authorized = 1 + WHERE id = ? + """, (x['subscriber_id'],)) + +hlr.close() +web.close() + diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 1a6a72ac6..4bdca2ab7 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -302,6 +302,8 @@ struct gsm_bts { * rather than starting from TRX0 and go upwards? */ int chan_alloc_reverse; int cell_barred; + /* maximum Tx power that the MS is permitted to use in this cell */ + int ms_max_power; /* how do we talk OML with this TRX? */ struct gsm_e1_subslot oml_e1_link; diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 0dc1772dc..1af849684 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -83,7 +83,6 @@ enum signal_lchan { enum signal_subscr { S_SUBSCR_ATTACHED, S_SUBSCR_DETACHED, - S_SUBSCR_FIRST_CONTACT, }; typedef int signal_cbfn(unsigned int subsys, unsigned int signal, diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index f107216c2..d54f2fd9f 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1082,7 +1082,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) arfcn = lchan->ts->trx->arfcn; subch = lchan->nr; - lchan->ms_power = ms_pwr_ctl_lvl(bts->band, 20 /* dBm == 100mW */); + lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); lchan->bs_power = 0; /* 0dB reduction, output power = Pn */ lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; rsl_chan_activate_lchan(lchan, 0x00, rqd_ta); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 15bc70cc1..4253959a8 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -956,7 +956,7 @@ static void patch_si_tables(struct gsm_bts *bts) /* patch MS max power for CCH */ type_4->cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, 20 /* dBm == 100mW */); + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); if (bts->cell_barred) { type_1->rach_control.cell_bar = 1; @@ -1115,7 +1115,6 @@ static void print_help() printf(" -s --disable-color\n"); printf(" -c --config-file filename The config file to use.\n"); printf(" -l --database db-name The database to use\n"); - printf(" -a --authorize-everyone Allow everyone into the network.\n"); printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -C --cardnr number For bs11 select E1 card number other than 0\n"); @@ -1165,9 +1164,6 @@ static void handle_options(int argc, char** argv) case 'c': config_file = strdup(optarg); break; - case 'a': - gsm0408_allow_everyone(1); - break; case 'r': gsm0408_set_reject_cause(atoi(optarg)); break; @@ -1222,6 +1218,7 @@ int main(int argc, char **argv) int rc; tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); + on_dso_load_token(); /* parse options */ handle_options(argc, argv); diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 938c5c440..0704bca2b 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -468,23 +468,24 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) { * an error. */ -int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token) { - dbi_result result=NULL; +int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token) +{ + dbi_result result; u_int32_t try; + for (;;) { try = rand(); if (!try) /* 0 is an invalid token */ continue; result = dbi_conn_queryf(conn, "SELECT * FROM AuthToken " - "WHERE subscriber_id = %llu OR token = %08x ", - subscriber->id, try - ); - if (result==NULL) { + "WHERE subscriber_id = %llu OR token = \"%08X\" ", + subscriber->id, try); + if (!result) { printf("DB: Failed to query AuthToken while allocating new token.\n"); return 1; } - if (dbi_result_get_numrows(result)){ + if (dbi_result_get_numrows(result)) { dbi_result_free(result); continue; } @@ -498,15 +499,16 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke "INSERT INTO AuthToken " "(subscriber_id, created, token) " "VALUES " - "(%llu, datetime('now'), %08x)) ", - subscriber->id, try - ); - if (result==NULL) { - printf("DB: Failed to create token %08x for IMSI %s.\n", try, subscriber->imsi); + "(%llu, datetime('now'), \"%08X\") ", + subscriber->id, try); + if (!result) { + printf("DB: Failed to create token %08X for IMSI %s.\n", try, subscriber->imsi); return 1; } + dbi_result_free(result); *token = try; - printf("DB: Allocated token %08x for IMSI %s.\n", try, subscriber->imsi); + printf("DB: Allocated token %08X for IMSI %s.\n", try, subscriber->imsi); + return 0; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f0ec3ff96..03fe01058 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -304,13 +305,6 @@ struct gsm_lai { u_int16_t lac; }; -static int authorize_everonye = 0; -void gsm0408_allow_everyone(int everyone) -{ - printf("Allowing everyone?\n"); - authorize_everonye = everyone; -} - static int reject_cause = 0; void gsm0408_set_reject_cause(int cause) { @@ -333,10 +327,16 @@ static int authorize_subscriber(struct gsm_loc_updating_operation *loc, if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei)) return 0; - if (authorize_everonye) + switch (subscriber->net->auth_policy) { + case GSM_AUTH_POLICY_CLOSED: + return subscriber->authorized; + case GSM_AUTH_POLICY_TOKEN: + return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT); + case GSM_AUTH_POLICY_ACCEPT_ALL: return 1; - - return subscriber->authorized; + default: + return 0; + } } static void release_loc_updating_req(struct gsm_lchan *lchan) @@ -1154,12 +1154,8 @@ static int mm_rx_id_resp(struct msgb *msg) /* look up subscriber based on IMSI, create if not found */ if (!lchan->subscr) { lchan->subscr = subscr_get_by_imsi(net, mi_string); - } - if (!lchan->subscr) { - lchan->subscr = db_create_subscriber(net, mi_string); - if (lchan->subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) { - dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &lchan->subscr); - } + if (!lchan->subscr) + lchan->subscr = db_create_subscriber(net, mi_string); } if (lchan->loc_operation) lchan->loc_operation->waiting_for_imsi = 0; @@ -1256,9 +1252,6 @@ static int mm_rx_loc_upd_req(struct msgb *msg) if (!subscr) { subscr = db_create_subscriber(bts->network, mi_string); } - if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) { - dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &subscr); - } break; case GSM_MI_TYPE_TMSI: DEBUGPC(DMM, "\n"); @@ -1343,7 +1336,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) struct gsm_network *net = lchan->ts->trx->bts->network; u_int8_t *ptr8; u_int16_t *ptr16; - int name_len; + int name_len, name_pad; int i; #if 0 time_t cur_t; @@ -1358,6 +1351,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) gh->msg_type = GSM48_MT_MM_INFO; if (net->name_long) { +#if 0 name_len = strlen(net->name_long); /* 10.5.3.5a */ ptr8 = msgb_put(msg, 3); @@ -1371,9 +1365,24 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) /* FIXME: Use Cell Broadcast, not UCS-2, since * UCS-2 is only supported by later revisions of the spec */ +#endif + name_len = (strlen(net->name_long)*7)/8; + name_pad = (8 - strlen(net->name_long)*7)%8; + if (name_pad > 0) + name_len++; + /* 10.5.3.5a */ + ptr8 = msgb_put(msg, 3); + ptr8[0] = GSM48_IE_NAME_LONG; + ptr8[1] = name_len +1; + ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */ + + ptr8 = msgb_put(msg, name_len); + gsm_7bit_encode(ptr8, net->name_long); + } if (net->name_short) { +#if 0 name_len = strlen(net->name_short); /* 10.5.3.5a */ ptr8 = (u_int8_t *) msgb_put(msg, 3); @@ -1384,6 +1393,20 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) ptr16 = (u_int16_t *) msgb_put(msg, name_len*2); for (i = 0; i < name_len; i++) ptr16[i] = htons(net->name_short[i]); +#endif + name_len = (strlen(net->name_short)*7)/8; + name_pad = (8 - strlen(net->name_short)*7)%8; + if (name_pad > 0) + name_len++; + /* 10.5.3.5a */ + ptr8 = (u_int8_t *) msgb_put(msg, 3); + ptr8[0] = GSM48_IE_NAME_SHORT; + ptr8[1] = name_len +1; + ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */ + + ptr8 = msgb_put(msg, name_len); + gsm_7bit_encode(ptr8, net->name_short); + } #if 0 @@ -1405,6 +1428,8 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) ptr8[7] |= 0x80; #endif + DEBUGP(DMM, "-> MM INFO\n"); + return gsm48_sendmsg(msg, NULL); } diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 16c5c079b..1b1368f82 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -175,6 +175,10 @@ static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) /* FIXME: implementation */ DEBUGP(DSMS, "VPI enhanced not implemented yet\n"); break; + case GSM340_TP_VPF_NONE: + /* Default validity: two days */ + minutes = 24 * 60 * 2; + break; } return minutes; } @@ -272,6 +276,7 @@ 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; + u_int8_t octet_len; unsigned int old_msg_len = msg->len; /* generate first octet with masked bits */ @@ -317,10 +322,13 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) /* generate TP-UD */ /* FIXME: Handle DSC of UCS2 or 8/bit default */ if (gsm338_get_sms_alphabet(sms->data_coding_scheme) == DCS_7BIT_DEFAULT) { + octet_len = sms->user_data_len*7/8; + if (sms->user_data_len*7%8 != 0) + octet_len++; /* Warning, user_data_len indicates the amount of septets * (characters), we need amount of octets occupied */ - smsp = msgb_put(msg, ceil(sms->user_data_len*7/8.0)); - memcpy(smsp, sms->user_data, ceil(sms->user_data_len*7/8.0)); + smsp = msgb_put(msg, octet_len); + memcpy(smsp, sms->user_data, octet_len); } return msg->len - old_msg_len; @@ -383,6 +391,9 @@ static int gsm340_rx_tpdu(struct msgb *msg) sms_vp = smsp; smsp += 7; break; + case GSM340_TP_VPF_NONE: + sms_vp = 0; + break; default: DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n", sms_vpf); @@ -954,6 +965,8 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal, struct gsm_lchan *lchan; struct gsm_sms *sms; + u_int32_t token; + switch (signal) { case S_SUBSCR_ATTACHED: /* A subscriber has attached. Check if there are diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 22e842280..7e8100dcb 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -151,6 +151,7 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->bsic = bsic; bts->num_trx = 0; INIT_LLIST_HEAD(&bts->trx_list); + bts->ms_max_power = 15; /* dBm */ /* create our primary TRX */ bts->c0 = gsm_bts_trx_alloc(bts); diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c index be951c415..6d4f14b2e 100644 --- a/openbsc/src/token_auth.c +++ b/openbsc/src/token_auth.c @@ -20,34 +20,94 @@ * */ +#include +#include #include #include #include #include #include +#include +#include -#define TOKEN_SMS_TEXT "HAR 2009 GSM. Please visit http://127.0.0.1/ to register" +#define TOKEN_SMS_TEXT "HAR 2009 GSM. Please visit http://har2009.gnumonks.org/ to" \ + "register. Your IMSI is %s, your auth token is %08X." + +static char *build_sms_string(struct gsm_subscriber *subscr, u_int32_t token) +{ + char *sms_str; + unsigned int len; + + len = strlen(subscr->imsi) + 8 + strlen(TOKEN_SMS_TEXT); + sms_str = talloc_size(tall_bsc_ctx, len); + if (!sms_str) + return NULL; + + snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->imsi, token); + sms_str[len-1] = '\0'; + + return sms_str; +} static int token_subscr_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_subscriber *subscr = signal_data; struct gsm_sms *sms; + int rc = 0; if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN) return 0; - switch (signal) { - case S_SUBSCR_FIRST_CONTACT: + if (signal != S_SUBSCR_ATTACHED) + return 0; + + if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) { + u_int32_t token; + char *sms_str; + /* we've seen this subscriber for the first time. */ - sms = sms_from_text(subscr, TOKEN_SMS_TEXT); - if (!sms) - return -ENOMEM; - gsm411_send_sms_subscr(subscr, sms); - break; + rc = db_subscriber_alloc_token(subscr, &token); + if (rc != 0) { + rc = -EIO; + goto unauth; + } + + sms_str = build_sms_string(subscr, token); + if (!sms_str) { + rc = -ENOMEM; + goto unauth; + } + + sms = sms_from_text(subscr, sms_str); + talloc_free(sms_str); + if (!sms) { + rc = -ENOMEM; + goto unauth; + } + + rc = gsm411_send_sms_subscr(subscr, sms); + + /* FIXME: else, delete the subscirber from database */ +unauth: + + /* make sure we don't allow him in again unless he clicks the web UI */ + subscr->authorized = 0; + db_sync_subscriber(subscr); + if (rc) { + struct gsm_lchan *lchan = lchan_for_subscr(subscr); + if (lchan) { + u_int8_t auth_rand[16]; + /* kick the subscriber off the network */ + gsm48_tx_mm_auth_req(lchan, auth_rand); + gsm48_tx_mm_auth_rej(lchan); + /* FIXME: close the channel early ?*/ + //gsm48_send_rr_Release(lchan); + } + } } - return 0; + return rc; } static int token_sms_cb(unsigned int subsys, unsigned int signal, @@ -55,37 +115,37 @@ static int token_sms_cb(unsigned int subsys, unsigned int signal, { struct gsm_sms *sms = signal_data; struct gsm_lchan *lchan; - u_int16_t rand[16]; + u_int8_t auth_rand[16]; + if (signal != S_SMS_DELIVERED) return 0; + /* these are not the droids we've been looking for */ if (!sms->receiver || !(sms->receiver->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) return 0; + if (sms->receiver->net->auth_policy != GSM_AUTH_POLICY_TOKEN) return 0; + lchan = lchan_for_subscr(sms->receiver); if (lchan) { /* kick the subscriber off the network */ - gsm48_tx_mm_auth_req(lchan, rand); + gsm48_tx_mm_auth_req(lchan, auth_rand); gsm48_tx_mm_auth_rej(lchan); - /* close the channel */ + /* FIXME: close the channel early ?*/ //gsm48_send_rr_Release(lchan); - lchan_free(lchan); } - /* make sure we don't allow him in again unless he clicks the web UI */ - sms->receiver->authorized = 0; - db_sync_subscriber(sms->receiver); - return 0; } -static __attribute__((constructor)) void on_dso_load_token(void) +//static __attribute__((constructor)) void on_dso_load_token(void) +void on_dso_load_token(void) { register_signal_handler(SS_SUBSCR, token_subscr_cb, NULL); register_signal_handler(SS_SMS, token_sms_cb, NULL); diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 70c5e01a7..4933bb4e9 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -233,6 +233,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) VTY_NEWLINE); vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); + vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); @@ -975,6 +976,17 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd, + "ms max power <0-40>", + "Maximum transmit power of the MS") +{ + struct gsm_bts *bts = vty->index; + + bts->ms_max_power = atoi(argv[0]); + + return CMD_SUCCESS; +} + /* per TRX configuration */ DEFUN(cfg_trx, @@ -1205,11 +1217,10 @@ int sms_from_text(struct gsm_subscriber *receiver, const char *text) if (!receiver->lac) { /* subscriber currently not attached, store in database? */ - subscr_put(sms->receiver); return CMD_WARNING; } - sms->receiver = receiver; + sms->receiver = subscr_get(receiver); strncpy(sms->text, text, sizeof(sms->text)-1); /* FIXME: don't use ID 1 static */ @@ -1233,7 +1244,7 @@ static int _send_sms_buffer(struct gsm_subscriber *receiver, sms = sms_from_text(receiver, buffer_getstr(b)); - gsm411_send_sms_subscr(sms->receiver, sms); + gsm411_send_sms_subscr(receiver, sms); return CMD_SUCCESS; } @@ -1374,6 +1385,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd); install_element(BTS_NODE, &cfg_bts_challoc_cmd); install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); + install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_trx_cmd);