blob: 8cfbb7c43c0a995ab0d26c6e9b3e7fe398e9454a [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>
27
28#include <osmocore/talloc.h>
29#include <osmocore/protocol/gsm_12_21.h>
30
31#include <sys/socket.h>
32#include <sys/un.h>
33
34#include <errno.h>
35#include <unistd.h>
36
37#define RF_CMD_QUERY '?'
38#define RF_CMD_OFF '0'
39#define RF_CMD_ON '1'
40
41static int lock_each_trx(struct gsm_network *net, int lock)
42{
43 struct gsm_bts *bts;
44
45 llist_for_each_entry(bts, &net->bts_list, list) {
46 struct gsm_bts_trx *trx;
47 llist_for_each_entry(trx, &bts->trx_list, list) {
48 gsm_trx_lock_rf(trx, lock);
49 }
50 }
51
52 return 0;
53}
54
55/*
56 * Send a '1' when one TRX is online, otherwise send 0
57 */
58static void handle_query(struct osmo_bsc_rf_conn *conn)
59{
60 struct msgb *msg;
61 struct gsm_bts *bts;
62 char send = RF_CMD_OFF;
63
64 llist_for_each_entry(bts, &conn->gsm_network->bts_list, list) {
65 struct gsm_bts_trx *trx;
66 llist_for_each_entry(trx, &bts->trx_list, list) {
67 if (trx->nm_state.availability == NM_AVSTATE_OK &&
68 trx->nm_state.operational != NM_STATE_LOCKED) {
69 send = RF_CMD_ON;
70 break;
71 }
72 }
73 }
74
75 msg = msgb_alloc(10, "RF Query");
76 if (!msg) {
77 LOGP(DINP, LOGL_ERROR, "Failed to allocate response msg.\n");
78 return;
79 }
80
81 msg->l2h = msgb_put(msg, 1);
82 msg->l2h[0] = send;
83
84 if (write_queue_enqueue(&conn->queue, msg) != 0) {
85 LOGP(DINP, LOGL_ERROR, "Failed to enqueue the answer.\n");
86 msgb_free(msg);
87 return;
88 }
89
90 return;
91}
92
93static int rf_read_cmd(struct bsc_fd *fd)
94{
95 struct osmo_bsc_rf_conn *conn = fd->data;
96 char buf[1];
97 int rc;
98
99 rc = read(fd->fd, buf, sizeof(buf));
100 if (rc != sizeof(buf)) {
101 LOGP(DINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno));
102 bsc_unregister_fd(fd);
103 close(fd->fd);
104 write_queue_clear(&conn->queue);
105 talloc_free(conn);
106 return -1;
107 }
108
109 switch (buf[0]) {
110 case RF_CMD_QUERY:
111 handle_query(conn);
112 break;
113 case RF_CMD_OFF:
114 lock_each_trx(conn->gsm_network, 1);
115 break;
116 case RF_CMD_ON:
117 lock_each_trx(conn->gsm_network, 0);
118 break;
119 default:
120 LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
121 break;
122 }
123
124 return 0;
125}
126
127static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
128{
129 int rc;
130
131 rc = write(fd->fd, msg->data, msg->len);
132 if (rc != msg->len) {
133 LOGP(DINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno));
134 return -1;
135 }
136
137 return 0;
138}
139
140static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
141{
142 struct osmo_bsc_rf_conn *conn;
143 struct osmo_bsc_rf *rf = bfd->data;
144 struct sockaddr_un addr;
145 socklen_t len = sizeof(addr);
146 int fd;
147
148 fd = accept(bfd->fd, (struct sockaddr *) &addr, &len);
149 if (fd < 0) {
150 LOGP(DINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n",
151 errno, strerror(errno));
152 return -1;
153 }
154
155 conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
156 if (!conn) {
157 LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
158 close(fd);
159 return -1;
160 }
161
162 write_queue_init(&conn->queue, 10);
163 conn->queue.bfd.data = conn;
164 conn->queue.bfd.fd = fd;
165 conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
166 conn->queue.read_cb = rf_read_cmd;
167 conn->queue.write_cb = rf_write_cmd;
168 conn->gsm_network = rf->gsm_network;
169
170 if (bsc_register_fd(&conn->queue.bfd) != 0) {
171 close(fd);
172 talloc_free(conn);
173 return -1;
174 }
175
176 return 0;
177}
178
179struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
180{
181 unsigned int namelen;
182 struct sockaddr_un local;
183 struct bsc_fd *bfd;
184 struct osmo_bsc_rf *rf;
185 int rc;
186
187 rf = talloc_zero(NULL, struct osmo_bsc_rf);
188 if (!rf) {
189 LOGP(DINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
190 return NULL;
191 }
192
193 bfd = &rf->listen;
194 bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0);
195 if (bfd->fd < 0) {
196 LOGP(DINP, LOGL_ERROR, "Can not create socket. %d/%s\n",
197 errno, strerror(errno));
198 return NULL;
199 }
200
201 local.sun_family = AF_UNIX;
202 strncpy(local.sun_path, path, sizeof(local.sun_path));
203 local.sun_path[sizeof(local.sun_path) - 1] = '\0';
204 unlink(local.sun_path);
205
206 /* we use the same magic that X11 uses in Xtranssock.c for
207 * calculating the proper length of the sockaddr */
208#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
209 local.sun_len = strlen(local.sun_path);
210#endif
211#if defined(BSD44SOCKETS) || defined(SUN_LEN)
212 namelen = SUN_LEN(&local);
213#else
214 namelen = strlen(local.sun_path) +
215 offsetof(struct sockaddr_un, sun_path);
216#endif
217
218 rc = bind(bfd->fd, (struct sockaddr *) &local, namelen);
219 if (rc != 0) {
220 LOGP(DINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n",
221 local.sun_path, errno, strerror(errno));
222 close(bfd->fd);
223 talloc_free(rf);
224 return NULL;
225 }
226
227 if (listen(bfd->fd, 0) != 0) {
228 LOGP(DINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno));
229 close(bfd->fd);
230 talloc_free(rf);
231 return NULL;
232 }
233
234 bfd->when = BSC_FD_READ;
235 bfd->cb = rf_ctl_accept;
236 bfd->data = rf;
237
238 if (bsc_register_fd(bfd) != 0) {
239 LOGP(DINP, LOGL_ERROR, "Failed to register bfd.\n");
240 close(bfd->fd);
241 talloc_free(rf);
242 return NULL;
243 }
244
245 rf->gsm_network = net;
246
247 return rf;
248}
249