blob: e45474ccb8a250fc3cb05a7e45b11cbdd4807a59 [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
66 llist_for_each_entry(bts, &conn->gsm_network->bts_list, list) {
67 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;
98 sig.net = conn->gsm_network;
99
100 dispatch_signal(SS_RF, val, &sig);
101}
102
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800103static int rf_read_cmd(struct bsc_fd *fd)
104{
105 struct osmo_bsc_rf_conn *conn = fd->data;
106 char buf[1];
107 int rc;
108
109 rc = read(fd->fd, buf, sizeof(buf));
110 if (rc != sizeof(buf)) {
111 LOGP(DINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno));
112 bsc_unregister_fd(fd);
113 close(fd->fd);
114 write_queue_clear(&conn->queue);
115 talloc_free(conn);
116 return -1;
117 }
118
119 switch (buf[0]) {
120 case RF_CMD_QUERY:
121 handle_query(conn);
122 break;
123 case RF_CMD_OFF:
124 lock_each_trx(conn->gsm_network, 1);
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +0800125 send_signal(conn, S_RF_OFF);
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800126 break;
127 case RF_CMD_ON:
128 lock_each_trx(conn->gsm_network, 0);
Holger Hans Peter Freyther12b917d2010-07-29 02:27:27 +0800129 send_signal(conn, S_RF_ON);
130 break;
131 case RF_CMD_GRACE:
132 send_signal(conn, S_RF_GRACE);
Holger Hans Peter Freyther2f4dbeb2010-06-30 14:29:53 +0800133 break;
134 default:
135 LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
136 break;
137 }
138
139 return 0;
140}
141
142static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
143{
144 int rc;
145
146 rc = write(fd->fd, msg->data, msg->len);
147 if (rc != msg->len) {
148 LOGP(DINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno));
149 return -1;
150 }
151
152 return 0;
153}
154
155static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
156{
157 struct osmo_bsc_rf_conn *conn;
158 struct osmo_bsc_rf *rf = bfd->data;
159 struct sockaddr_un addr;
160 socklen_t len = sizeof(addr);
161 int fd;
162
163 fd = accept(bfd->fd, (struct sockaddr *) &addr, &len);
164 if (fd < 0) {
165 LOGP(DINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n",
166 errno, strerror(errno));
167 return -1;
168 }
169
170 conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
171 if (!conn) {
172 LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
173 close(fd);
174 return -1;
175 }
176
177 write_queue_init(&conn->queue, 10);
178 conn->queue.bfd.data = conn;
179 conn->queue.bfd.fd = fd;
180 conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
181 conn->queue.read_cb = rf_read_cmd;
182 conn->queue.write_cb = rf_write_cmd;
183 conn->gsm_network = rf->gsm_network;
184
185 if (bsc_register_fd(&conn->queue.bfd) != 0) {
186 close(fd);
187 talloc_free(conn);
188 return -1;
189 }
190
191 return 0;
192}
193
194struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
195{
196 unsigned int namelen;
197 struct sockaddr_un local;
198 struct bsc_fd *bfd;
199 struct osmo_bsc_rf *rf;
200 int rc;
201
202 rf = talloc_zero(NULL, struct osmo_bsc_rf);
203 if (!rf) {
204 LOGP(DINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
205 return NULL;
206 }
207
208 bfd = &rf->listen;
209 bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0);
210 if (bfd->fd < 0) {
211 LOGP(DINP, LOGL_ERROR, "Can not create socket. %d/%s\n",
212 errno, strerror(errno));
213 return NULL;
214 }
215
216 local.sun_family = AF_UNIX;
217 strncpy(local.sun_path, path, sizeof(local.sun_path));
218 local.sun_path[sizeof(local.sun_path) - 1] = '\0';
219 unlink(local.sun_path);
220
221 /* we use the same magic that X11 uses in Xtranssock.c for
222 * calculating the proper length of the sockaddr */
223#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
224 local.sun_len = strlen(local.sun_path);
225#endif
226#if defined(BSD44SOCKETS) || defined(SUN_LEN)
227 namelen = SUN_LEN(&local);
228#else
229 namelen = strlen(local.sun_path) +
230 offsetof(struct sockaddr_un, sun_path);
231#endif
232
233 rc = bind(bfd->fd, (struct sockaddr *) &local, namelen);
234 if (rc != 0) {
235 LOGP(DINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n",
236 local.sun_path, errno, strerror(errno));
237 close(bfd->fd);
238 talloc_free(rf);
239 return NULL;
240 }
241
242 if (listen(bfd->fd, 0) != 0) {
243 LOGP(DINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno));
244 close(bfd->fd);
245 talloc_free(rf);
246 return NULL;
247 }
248
249 bfd->when = BSC_FD_READ;
250 bfd->cb = rf_ctl_accept;
251 bfd->data = rf;
252
253 if (bsc_register_fd(bfd) != 0) {
254 LOGP(DINP, LOGL_ERROR, "Failed to register bfd.\n");
255 close(bfd->fd);
256 talloc_free(rf);
257 return NULL;
258 }
259
260 rf->gsm_network = net;
261
262 return rf;
263}
264