blob: 06c84666c7762f7f238acecab0e9e65b706bcdad [file] [log] [blame]
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +08001/* RF Ctl handling socket */
2
3/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2010 by On-Waves
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24#include <openbsc/osmo_bsc_rf.h>
25#include <openbsc/debug.h>
26#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +080027#include <openbsc/signal.h>
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +080028
29#include <osmocore/talloc.h>
30#include <osmocore/protocol/gsm_12_21.h>
31
32#include <sys/socket.h>
33#include <sys/un.h>
34
35#include <errno.h>
36#include <unistd.h>
37
38#define RF_CMD_QUERY '?'
39#define RF_CMD_OFF '0'
40#define RF_CMD_ON '1'
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +080041#define RF_CMD_GRACE 'g'
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +080042
43static int lock_each_trx(struct gsm_network *net, int lock)
44{
45 struct gsm_bts *bts;
46
47 llist_for_each_entry(bts, &net->bts_list, list) {
48 struct gsm_bts_trx *trx;
49 llist_for_each_entry(trx, &bts->trx_list, list) {
50 gsm_trx_lock_rf(trx, lock);
51 }
52 }
53
54 return 0;
55}
56
57/*
58 * Send a '1' when one TRX is online, otherwise send 0
59 */
60static void handle_query(struct osmo_bsc_rf_conn *conn)
61{
62 struct msgb *msg;
63 struct gsm_bts *bts;
64 char send = RF_CMD_OFF;
65
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +080066 llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +080067 struct gsm_bts_trx *trx;
68 llist_for_each_entry(trx, &bts->trx_list, list) {
69 if (trx->nm_state.availability == NM_AVSTATE_OK &&
70 trx->nm_state.operational != NM_STATE_LOCKED) {
71 send = RF_CMD_ON;
72 break;
73 }
74 }
75 }
76
77 msg = msgb_alloc(10, "RF Query");
78 if (!msg) {
79 LOGP(DINP, LOGL_ERROR, "Failed to allocate response msg.\n");
80 return;
81 }
82
83 msg->l2h = msgb_put(msg, 1);
84 msg->l2h[0] = send;
85
86 if (write_queue_enqueue(&conn->queue, msg) != 0) {
87 LOGP(DINP, LOGL_ERROR, "Failed to enqueue the answer.\n");
88 msgb_free(msg);
89 return;
90 }
91
92 return;
93}
94
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +080095static void send_signal(struct osmo_bsc_rf_conn *conn, int val)
96{
97 struct rf_signal_data sig;
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +080098 sig.net = conn->rf->gsm_network;
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +080099
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +0800100 conn->rf->policy = val;
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +0800101 dispatch_signal(SS_RF, val, &sig);
102}
103
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800104static int rf_read_cmd(struct bsc_fd *fd)
105{
106 struct osmo_bsc_rf_conn *conn = fd->data;
107 char buf[1];
108 int rc;
109
110 rc = read(fd->fd, buf, sizeof(buf));
111 if (rc != sizeof(buf)) {
112 LOGP(DINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno));
113 bsc_unregister_fd(fd);
114 close(fd->fd);
115 write_queue_clear(&conn->queue);
116 talloc_free(conn);
117 return -1;
118 }
119
120 switch (buf[0]) {
121 case RF_CMD_QUERY:
122 handle_query(conn);
123 break;
124 case RF_CMD_OFF:
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +0800125 lock_each_trx(conn->rf->gsm_network, 1);
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +0800126 send_signal(conn, S_RF_OFF);
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800127 break;
128 case RF_CMD_ON:
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +0800129 lock_each_trx(conn->rf->gsm_network, 0);
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +0800130 send_signal(conn, S_RF_ON);
131 break;
132 case RF_CMD_GRACE:
133 send_signal(conn, S_RF_GRACE);
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800134 break;
135 default:
136 LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
137 break;
138 }
139
140 return 0;
141}
142
143static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
144{
145 int rc;
146
147 rc = write(fd->fd, msg->data, msg->len);
148 if (rc != msg->len) {
149 LOGP(DINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno));
150 return -1;
151 }
152
153 return 0;
154}
155
156static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
157{
158 struct osmo_bsc_rf_conn *conn;
159 struct osmo_bsc_rf *rf = bfd->data;
160 struct sockaddr_un addr;
161 socklen_t len = sizeof(addr);
162 int fd;
163
164 fd = accept(bfd->fd, (struct sockaddr *) &addr, &len);
165 if (fd < 0) {
166 LOGP(DINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n",
167 errno, strerror(errno));
168 return -1;
169 }
170
171 conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
172 if (!conn) {
173 LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
174 close(fd);
175 return -1;
176 }
177
178 write_queue_init(&conn->queue, 10);
179 conn->queue.bfd.data = conn;
180 conn->queue.bfd.fd = fd;
181 conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
182 conn->queue.read_cb = rf_read_cmd;
183 conn->queue.write_cb = rf_write_cmd;
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +0800184 conn->rf = rf;
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800185
186 if (bsc_register_fd(&conn->queue.bfd) != 0) {
187 close(fd);
188 talloc_free(conn);
189 return -1;
190 }
191
192 return 0;
193}
194
195struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
196{
197 unsigned int namelen;
198 struct sockaddr_un local;
199 struct bsc_fd *bfd;
200 struct osmo_bsc_rf *rf;
201 int rc;
202
203 rf = talloc_zero(NULL, struct osmo_bsc_rf);
204 if (!rf) {
205 LOGP(DINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
206 return NULL;
207 }
208
209 bfd = &rf->listen;
210 bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0);
211 if (bfd->fd < 0) {
212 LOGP(DINP, LOGL_ERROR, "Can not create socket. %d/%s\n",
213 errno, strerror(errno));
214 return NULL;
215 }
216
217 local.sun_family = AF_UNIX;
218 strncpy(local.sun_path, path, sizeof(local.sun_path));
219 local.sun_path[sizeof(local.sun_path) - 1] = '\0';
220 unlink(local.sun_path);
221
222 /* we use the same magic that X11 uses in Xtranssock.c for
223 * calculating the proper length of the sockaddr */
224#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
225 local.sun_len = strlen(local.sun_path);
226#endif
227#if defined(BSD44SOCKETS) || defined(SUN_LEN)
228 namelen = SUN_LEN(&local);
229#else
230 namelen = strlen(local.sun_path) +
231 offsetof(struct sockaddr_un, sun_path);
232#endif
233
234 rc = bind(bfd->fd, (struct sockaddr *) &local, namelen);
235 if (rc != 0) {
236 LOGP(DINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n",
237 local.sun_path, errno, strerror(errno));
238 close(bfd->fd);
239 talloc_free(rf);
240 return NULL;
241 }
242
243 if (listen(bfd->fd, 0) != 0) {
244 LOGP(DINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno));
245 close(bfd->fd);
246 talloc_free(rf);
247 return NULL;
248 }
249
250 bfd->when = BSC_FD_READ;
251 bfd->cb = rf_ctl_accept;
252 bfd->data = rf;
253
254 if (bsc_register_fd(bfd) != 0) {
255 LOGP(DINP, LOGL_ERROR, "Failed to register bfd.\n");
256 close(bfd->fd);
257 talloc_free(rf);
258 return NULL;
259 }
260
261 rf->gsm_network = net;
Holger Hans Peter Freyther7a1591b2010-09-16 00:10:18 +0800262 rf->policy = S_RF_ON;
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800263
264 return rf;
265}
266