Merge branch 'holger/merge-on-waves-msc'

This commit is contained in:
Holger Hans Peter Freyther 2009-09-28 12:57:27 +02:00
commit 51a7b9a973
17 changed files with 167 additions and 98 deletions

View file

@ -203,7 +203,7 @@ struct gsm48_system_information_type_6 {
u_int8_t rr_protocol_discriminator :4,
skip_indicator:4;
u_int8_t system_information;
u_int8_t cell_identity[2];
u_int16_t cell_identity;
struct gsm48_loc_area_id lai;
u_int8_t cell_options;
u_int8_t ncc_permitted;
@ -736,4 +736,8 @@ int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
extern const char *gsm0408_cc_msg_names[];
int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
#endif

View file

@ -298,6 +298,8 @@ struct gsm_bts {
struct gsm_network *network;
/* number of ths BTS in network */
u_int8_t nr;
/* Cell Identity */
u_int16_t cell_identity;
/* location area code of this BTS */
u_int8_t location_area_code;
/* Training Sequence Code */

View file

@ -7,14 +7,17 @@
#define GSM_IMEI_LENGTH 17
#define GSM_IMSI_LENGTH 17
#define GSM_TMSI_LENGTH 17
#define GSM_NAME_LENGTH 128
#define GSM_EXTENSION_LENGTH 128
/* reserved according to GSM 03.03 § 2.4 */
#define GSM_RESERVED_TMSI 0xFFFFFFFF
#define GSM_MIN_EXTEN 20000
#define GSM_MAX_EXTEN 49999
#define GSM_SUBSCRIBER_FIRST_CONTACT 0x00000001
#define tmsi_from_string(str) strtoul(str, NULL, 10)
struct gsm_equipment {
long long unsigned int id;
@ -32,7 +35,7 @@ struct gsm_subscriber {
struct gsm_network *net;
long long unsigned int id;
char imsi[GSM_IMSI_LENGTH];
char tmsi[GSM_TMSI_LENGTH];
u_int32_t tmsi;
u_int16_t lac;
char name[GSM_NAME_LENGTH];
char extension[GSM_EXTENSION_LENGTH];
@ -70,7 +73,7 @@ enum gsm_subscriber_update_reason {
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net,
const char *tmsi);
u_int32_t tmsi);
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,

View file

@ -916,6 +916,10 @@ static void patch_si_tables(struct gsm_bts *bts)
type_4->lai = lai;
type_6->lai = lai;
/* set the CI */
type_3->cell_identity = htons(bts->cell_identity);
type_6->cell_identity = htons(bts->cell_identity);
type_4->data[2] &= 0xf0;
type_4->data[2] |= arfcn_high;
type_4->data[3] = arfcn_low;

View file

@ -376,7 +376,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
string = dbi_result_get_string(result, "tmsi");
if (string)
strncpy(subscr->tmsi, string, GSM_TMSI_LENGTH);
subscr->tmsi = tmsi_from_string(string);
string = dbi_result_get_string(result, "name");
if (string)
@ -388,7 +388,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
subscr->lac = dbi_result_get_uint(result, "lac");
subscr->authorized = dbi_result_get_uint(result, "authorized");
printf("DB: Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %s, EXTEN '%s', LAC %hu, AUTH %u\n",
printf("DB: Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
subscr->lac, subscr->authorized);
dbi_result_free(result);
@ -400,12 +400,15 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
int db_sync_subscriber(struct gsm_subscriber* subscriber) {
dbi_result result;
char tmsi[14];
char *q_tmsi;
if (subscriber->tmsi[0])
if (subscriber->tmsi != GSM_RESERVED_TMSI) {
sprintf(tmsi, "%u", subscriber->tmsi);
dbi_conn_quote_string_copy(conn,
subscriber->tmsi,
tmsi,
&q_tmsi);
else
} else
q_tmsi = strdup("NULL");
result = dbi_conn_queryf(conn,
"UPDATE Subscriber "
@ -475,10 +478,15 @@ int db_sync_equipment(struct gsm_equipment *equip)
int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
dbi_result result=NULL;
char tmsi[14];
char* tmsi_quoted;
for (;;) {
sprintf(subscriber->tmsi, "%i", rand());
dbi_conn_quote_string_copy(conn, subscriber->tmsi, &tmsi_quoted);
subscriber->tmsi = rand();
if (subscriber->tmsi == GSM_RESERVED_TMSI)
continue;
sprintf(tmsi, "%u", subscriber->tmsi);
dbi_conn_quote_string_copy(conn, tmsi, &tmsi_quoted);
result = dbi_conn_queryf(conn,
"SELECT * FROM Subscriber "
"WHERE tmsi = %s ",
@ -495,7 +503,7 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
}
if (!dbi_result_next_row(result)) {
dbi_result_free(result);
printf("DB: Allocated TMSI %s for IMSI %s.\n", subscriber->tmsi, subscriber->imsi);
printf("DB: Allocated TMSI %u for IMSI %s.\n", subscriber->tmsi, subscriber->imsi);
return db_sync_subscriber(subscriber);
}
dbi_result_free(result);

View file

@ -291,15 +291,12 @@ static void allocate_loc_updating_req(struct gsm_lchan *lchan)
static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
{
u_int32_t tmsi;
if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
int rc;
db_subscriber_alloc_tmsi(lchan->subscr);
tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
release_loc_updating_req(lchan);
rc = gsm0408_loc_upd_acc(msg->lchan, tmsi);
rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi);
/* call subscr_update after putting the loc_upd_acc
* in the transmit queue, since S_SUBSCR_ATTACHED might
* trigger further action like SMS delivery */
@ -1054,7 +1051,8 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
lchan->loc_operation->waiting_for_imei = 1;
/* look up the subscriber based on TMSI, request IMSI if it fails */
subscr = subscr_get_by_tmsi(bts->network, mi_string);
subscr = subscr_get_by_tmsi(bts->network,
tmsi_from_string(mi_string));
if (!subscr) {
/* send IDENTITY REQUEST message to get IMSI */
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
@ -1284,22 +1282,6 @@ static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
return gsm48_sendmsg(msg, NULL);
}
static int send_siemens_mrpci(struct gsm_lchan *lchan,
u_int8_t *classmark2_lv)
{
struct rsl_mrpci mrpci;
if (classmark2_lv[0] < 2)
return -EINVAL;
mrpci.power_class = classmark2_lv[1] & 0x7;
mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
return rsl_siemens_mrpci(lchan, &mrpci);
}
/*
* Handle CM Service Requests
* a) Verify that the packet is long enough to contain the information
@ -1352,7 +1334,8 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg)
if (is_siemens_bts(bts))
send_siemens_mrpci(msg->lchan, classmark2-1);
subscr = subscr_get_by_tmsi(bts->network, mi_string);
subscr = subscr_get_by_tmsi(bts->network,
tmsi_from_string(mi_string));
/* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
if (!subscr)
@ -1389,7 +1372,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
switch (mi_type) {
case GSM_MI_TYPE_TMSI:
subscr = subscr_get_by_tmsi(bts->network, mi_string);
subscr = subscr_get_by_tmsi(bts->network,
tmsi_from_string(mi_string));
break;
case GSM_MI_TYPE_IMSI:
subscr = subscr_get_by_imsi(bts->network, mi_string);
@ -1479,23 +1463,19 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t *classmark2_lv = gh->data + 1;
u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
u_int8_t mi_type;
char mi_string[GSM48_MI_SIZE];
struct gsm_subscriber *subscr = NULL;
struct paging_signal_data sig_data;
int rc = 0;
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
if (is_siemens_bts(bts))
send_siemens_mrpci(msg->lchan, classmark2_lv);
switch (mi_type) {
case GSM_MI_TYPE_TMSI:
subscr = subscr_get_by_tmsi(bts->network, mi_string);
subscr = subscr_get_by_tmsi(bts->network,
tmsi_from_string(mi_string));
break;
case GSM_MI_TYPE_IMSI:
subscr = subscr_get_by_imsi(bts->network, mi_string);
@ -1514,30 +1494,7 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv);
db_sync_equipment(&subscr->equipment);
if (!msg->lchan->subscr) {
msg->lchan->subscr = subscr;
} else if (msg->lchan->subscr != subscr) {
DEBUGP(DRR, "<- Channel already owned by someone else?\n");
subscr_put(subscr);
return -EINVAL;
} else {
DEBUGP(DRR, "<- Channel already owned by us\n");
subscr_put(subscr);
subscr = msg->lchan->subscr;
}
sig_data.subscr = subscr;
sig_data.bts = msg->lchan->ts->trx->bts;
sig_data.lchan = msg->lchan;
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
/* Stop paging on the bts we received the paging response */
paging_request_stop(msg->trx->bts, subscr, msg->lchan);
/* FIXME: somehow signal the completion of the PAGING to
* the entity that requested the paging */
rc = gsm48_handle_paging_resp(msg, subscr);
return rc;
}

View file

@ -25,12 +25,15 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <openbsc/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/transaction.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#define GSM48_ALLOC_SIZE 1024
#define GSM48_ALLOC_HEADROOM 128
@ -395,3 +398,62 @@ int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, cons
return str_cur - string;
}
int send_siemens_mrpci(struct gsm_lchan *lchan,
u_int8_t *classmark2_lv)
{
struct rsl_mrpci mrpci;
if (classmark2_lv[0] < 2)
return -EINVAL;
mrpci.power_class = classmark2_lv[1] & 0x7;
mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
return rsl_siemens_mrpci(lchan, &mrpci);
}
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t *classmark2_lv = gh->data + 1;
u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
}
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
{
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t *classmark2_lv = gh->data + 1;
struct paging_signal_data sig_data;
if (is_siemens_bts(bts))
send_siemens_mrpci(msg->lchan, classmark2_lv);
if (!msg->lchan->subscr) {
msg->lchan->subscr = subscr;
} else if (msg->lchan->subscr != subscr) {
DEBUGP(DRR, "<- Channel already owned by someone else?\n");
subscr_put(subscr);
return -EINVAL;
} else {
DEBUGP(DRR, "<- Channel already owned by us\n");
subscr_put(subscr);
subscr = msg->lchan->subscr;
}
sig_data.subscr = subscr;
sig_data.bts = msg->lchan->ts->trx->bts;
sig_data.lchan = msg->lchan;
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
/* Stop paging on the bts we received the paging response */
paging_request_stop(msg->trx->bts, subscr, msg->lchan);
return 0;
}

View file

@ -274,7 +274,7 @@ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
continue;
}
if (bts->location_area_code == lac)
if (lac == 0 || bts->location_area_code == lac)
return bts;
}
return NULL;

View file

@ -35,17 +35,19 @@
extern struct llist_head *subscr_bsc_active_subscriber(void);
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net,
const char *tmsi)
u_int32_t tmsi)
{
char tmsi_string[14];
struct gsm_subscriber *subscr;
/* we might have a record in memory already */
llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
if (strcmp(subscr->tmsi, tmsi) == 0)
if (tmsi == subscr->tmsi)
return subscr_get(subscr);
}
return db_get_subscriber(net, GSM_SUBSCRIBER_TMSI, tmsi);
sprintf(tmsi_string, "%u", tmsi);
return db_get_subscriber(net, GSM_SUBSCRIBER_TMSI, tmsi_string);
}
struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net,

View file

@ -73,7 +73,9 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
struct subscr_request *request;
struct gsm_subscriber *subscr = (struct gsm_subscriber *)param;
assert(!llist_empty(&subscr->requests));
/* There is no request anymore... */
if (llist_empty(&subscr->requests))
return -1;
/*
* FIXME: What to do with paging requests coming during
@ -94,11 +96,19 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
static void subscr_send_paging_request(struct gsm_subscriber *subscr)
{
struct subscr_request *request;
int rc;
assert(!llist_empty(&subscr->requests));
request = (struct subscr_request *)subscr->requests.next;
paging_request(subscr->net, subscr, request->channel_type,
subscr_paging_cb, subscr);
rc = paging_request(subscr->net, subscr, request->channel_type,
subscr_paging_cb, subscr);
/* paging failed, quit now */
if (rc <= 0) {
subscr_paging_cb(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
NULL, NULL, request->param);
}
}
struct gsm_subscriber *subscr_alloc(void)
@ -112,6 +122,7 @@ struct gsm_subscriber *subscr_alloc(void)
memset(s, 0, sizeof(*s));
llist_add_tail(&s->entry, &active_subscribers);
s->use_count = 1;
s->tmsi = GSM_RESERVED_TMSI;
INIT_LLIST_HEAD(&s->requests);

View file

@ -14,6 +14,7 @@ network
bts 0
type bs11
band GSM900
cell_identity 1
location_area_code 1
training_sequence_code 7
base_station_id_code 63

View file

@ -14,6 +14,7 @@ network
bts 0
type bs11
band GSM900
cell_identity 1
location_area_code 1
training_sequence_code 7
base_station_id_code 63

View file

@ -14,6 +14,7 @@ network
bts 0
type bs11
band GSM900
cell_identity 1
location_area_code 1
training_sequence_code 7
base_station_id_code 63

View file

@ -46,9 +46,6 @@
#include <openbsc/abis_rsl.h>
#include <openbsc/gsm_data.h>
#define PAGING_TIMEOUT 1, 75000
#define MAX_PAGING_REQUEST 750
void *tall_paging_ctx;
static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber *subscr)
@ -90,16 +87,18 @@ static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
static void page_ms(struct gsm_paging_request *request)
{
u_int8_t mi[128];
unsigned long int tmsi;
unsigned int mi_len;
unsigned int page_group;
DEBUGP(DPAG, "Going to send paging commands: '%s'\n",
request->subscr->imsi);
DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
request->subscr->imsi, request->subscr->tmsi);
if (request->subscr->tmsi == GSM_RESERVED_TMSI)
mi_len = gsm48_generate_mid_from_imsi(mi, request->subscr->imsi);
else
mi_len = gsm48_generate_mid_from_tmsi(mi, request->subscr->tmsi);
page_group = calculate_group(request->bts, request->subscr);
tmsi = strtoul(request->subscr->tmsi, NULL, 10);
mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
rsl_paging_cmd(request->bts, page_group, mi_len, mi,
request->chan_type);
}
@ -296,7 +295,8 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
{
struct gsm_bts *bts = NULL;
_paging_request_stop(_bts, subscr, lchan);
if (_bts)
_paging_request_stop(_bts, subscr, lchan);
do {
/*
@ -305,7 +305,7 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
* location area of the _bts as reconfiguration of the
* network is probably happening less often.
*/
bts = gsm_bts_by_lac(_bts->network, subscr->lac, bts);
bts = gsm_bts_by_lac(subscr->net, subscr->lac, bts);
if (!bts)
break;

View file

@ -102,15 +102,7 @@ void trans_free(struct gsm_trans *trans)
if (!trans->lchan && trans->subscr && trans->subscr->net) {
/* Stop paging on all bts' */
bts = NULL;
do {
bts = gsm_bts_by_lac(trans->subscr->net,
trans->subscr->lac, bts);
if (!bts)
break;
/* Stop paging */
paging_request_stop(bts, trans->subscr, NULL);
} while (1);
paging_request_stop(NULL, trans->subscr, NULL);
}
if (trans->subscr)

View file

@ -118,9 +118,10 @@ static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
{
vty_out(vty, "BTS %u is of %s type in band %s, has LAC %u, "
vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, "
"BSIC %u, TSC %u and %u TRX%s",
bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
bts->cell_identity,
bts->location_area_code, bts->bsic, bts->tsc,
bts->num_trx, VTY_NEWLINE);
if (bts->cell_barred)
@ -223,6 +224,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE);
vty_out(vty, " band %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
vty_out(vty, " cell_identity %u%s", bts->cell_identity, VTY_NEWLINE);
vty_out(vty, " location_area_code %u%s", bts->location_area_code,
VTY_NEWLINE);
vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
@ -427,8 +429,8 @@ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
VTY_NEWLINE);
if (subscr->imsi)
vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
if (subscr->tmsi)
vty_out(vty, " TMSI: %08X%s", atoi(subscr->tmsi),
if (subscr->tmsi != GSM_RESERVED_TMSI)
vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
VTY_NEWLINE);
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
}
@ -839,6 +841,24 @@ DEFUN(cfg_bts_band,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_ci,
cfg_bts_ci_cmd,
"cell_identity <0-65535>",
"Set the Cell identity of this BTS\n")
{
struct gsm_bts *bts = vty->index;
int ci = atoi(argv[0]);
if (ci < 0 || ci > 0xffff) {
vty_out(vty, "%% CI %d is not in the valid range (0-65535)%s",
ci, VTY_NEWLINE);
return CMD_WARNING;
}
bts->cell_identity = ci;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_lac,
cfg_bts_lac_cmd,
"location_area_code <0-255>",
@ -1175,6 +1195,7 @@ int bsc_vty_init(struct gsm_network *net)
install_default(BTS_NODE);
install_element(BTS_NODE, &cfg_bts_type_cmd);
install_element(BTS_NODE, &cfg_bts_band_cmd);
install_element(BTS_NODE, &cfg_bts_ci_cmd);
install_element(BTS_NODE, &cfg_bts_lac_cmd);
install_element(BTS_NODE, &cfg_bts_tsc_cmd);
install_element(BTS_NODE, &cfg_bts_bsic_cmd);

View file

@ -38,8 +38,8 @@
if (strcmp(original->imsi, copy->imsi) != 0) \
fprintf(stderr, "IMSIs do not match in %s:%d '%s' '%s'\n", \
__FUNCTION__, __LINE__, original->imsi, copy->imsi); \
if (strcmp(original->tmsi, copy->tmsi) != 0) \
fprintf(stderr, "TMSIs do not match in %s:%d '%s' '%s'\n", \
if (original->tmsi != copy->tmsi) \
fprintf(stderr, "TMSIs do not match in %s:%d '%u' '%u'\n", \
__FUNCTION__, __LINE__, original->tmsi, copy->tmsi); \
if (strcmp(original->name, copy->name) != 0) \
fprintf(stderr, "names do not match in %s:%d '%s' '%s'\n", \