aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc/meas_feed.c
blob: 3ddcdc39c8ccb2cbd89679622f0c979bc2847c7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* UDP-Feed of measurement reports */

#include <unistd.h>

#include <sys/socket.h>

#include <osmocom/core/msgb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>

#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>

#include <openbsc/meas_rep.h>
#include <openbsc/signal.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/meas_feed.h>
#include <openbsc/vty.h>

#include "meas_feed.h"

struct meas_feed_state {
	struct osmo_wqueue wqueue;
	char scenario[31+1];
	char *dst_host;
	uint16_t dst_port;
};


static struct meas_feed_state g_mfs;

static int process_meas_rep(struct gsm_meas_rep *mr)
{
	struct msgb *msg;
	struct meas_feed_meas *mfm;
	struct gsm_subscriber *subscr;

	/* ignore measurements as long as we don't know who it is */
	if (!mr->lchan || !mr->lchan->conn || !mr->lchan->conn->subscr)
		return 0;

	subscr = mr->lchan->conn->subscr;

	msg = msgb_alloc(sizeof(struct meas_feed_meas), "Meas. Feed");
	if (!msg)
		return 0;

	/* fill in the header */
	mfm = (struct meas_feed_meas *) msgb_put(msg, sizeof(*mfm));
	mfm->hdr.msg_type = MEAS_FEED_MEAS;
	mfm->hdr.version = MEAS_FEED_VERSION;

	/* fill in MEAS_FEED_MEAS specific header */
	osmo_strlcpy(mfm->imsi, subscr->imsi, sizeof(mfm->imsi));
	osmo_strlcpy(mfm->name, subscr->name, sizeof(mfm->name));
	osmo_strlcpy(mfm->scenario, g_mfs.scenario, sizeof(mfm->scenario));

	/* copy the entire measurement report */
	memcpy(&mfm->mr, mr, sizeof(mfm->mr));

	/* copy channel information */
	/* we assume that the measurement report always belong to some timeslot */
	mfm->lchan_type = (uint8_t)mr->lchan->type;
	mfm->pchan_type = (uint8_t)mr->lchan->ts->pchan;
	mfm->bts_nr = mr->lchan->ts->trx->bts->nr;
	mfm->trx_nr = mr->lchan->ts->trx->nr;
	mfm->ts_nr = mr->lchan->ts->nr;
	mfm->ss_nr = mr->lchan->nr;

	/* and send it to the socket */
	if (osmo_wqueue_enqueue(&g_mfs.wqueue, msg) != 0)
		msgb_free(msg);

	return 0;
}

static int meas_feed_sig_cb(unsigned int subsys, unsigned int signal,
			    void *handler_data, void *signal_data)
{
	struct lchan_signal_data *sdata = signal_data;

	if (subsys != SS_LCHAN)
		return 0;

	if (signal == S_LCHAN_MEAS_REP)
		process_meas_rep(sdata->mr);

	return 0;
}

static int feed_write_cb(struct osmo_fd *ofd, struct msgb *msg)
{
	return write(ofd->fd, msgb_data(msg), msgb_length(msg));
}

static int feed_read_cb(struct osmo_fd *ofd)
{
	int rc;
	char buf[256];

	rc = read(ofd->fd, buf, sizeof(buf));
	ofd->fd &= ~BSC_FD_READ;

	return rc;
}

int meas_feed_cfg_set(const char *dst_host, uint16_t dst_port)
{
	int rc;
	int already_initialized = 0;

	if (g_mfs.wqueue.bfd.fd)
		already_initialized = 1;


	if (already_initialized &&
	    !strcmp(dst_host, g_mfs.dst_host) &&
	    dst_port == g_mfs.dst_port)
		return 0;

	if (!already_initialized) {
		osmo_wqueue_init(&g_mfs.wqueue, 10);
		g_mfs.wqueue.write_cb = feed_write_cb;
		g_mfs.wqueue.read_cb = feed_read_cb;
		osmo_signal_register_handler(SS_LCHAN, meas_feed_sig_cb, NULL);
	}

	if (already_initialized) {
		osmo_wqueue_clear(&g_mfs.wqueue);
		osmo_fd_unregister(&g_mfs.wqueue.bfd);
		close(g_mfs.wqueue.bfd.fd);
		/* don't set to zero, as that would mean 'not yet initialized' */
		g_mfs.wqueue.bfd.fd = -1;
	}
	rc = osmo_sock_init_ofd(&g_mfs.wqueue.bfd, AF_UNSPEC, SOCK_DGRAM,
				IPPROTO_UDP, dst_host, dst_port,
				OSMO_SOCK_F_CONNECT);
	if (rc < 0)
		return rc;

	g_mfs.wqueue.bfd.when &= ~BSC_FD_READ;

	if (g_mfs.dst_host)
		talloc_free(g_mfs.dst_host);
	g_mfs.dst_host = talloc_strdup(NULL, dst_host);
	g_mfs.dst_port = dst_port;

	return 0;
}

void meas_feed_cfg_get(char **host, uint16_t *port)
{
	*port = g_mfs.dst_port;
	*host = g_mfs.dst_host;
}

void meas_feed_scenario_set(const char *name)
{
	osmo_strlcpy(g_mfs.scenario, name, sizeof(g_mfs.scenario));
}

const char *meas_feed_scenario_get(void)
{
	return g_mfs.scenario;
}