blob: 55658cf7a65754f4b3a795522cfec30eb5ff3523 [file] [log] [blame]
Harald Welte2ca7c312009-12-23 22:44:04 +01001/* OpenBSC Abis/IP proxy ip.access nanoBTS */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freyther85531cc2010-10-06 20:37:09 +08004 * (C) 2010 by On-Waves
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08005 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte2ca7c312009-12-23 22:44:04 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +010010 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
Harald Welte2ca7c312009-12-23 22:44:04 +010012 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * GNU Affero General Public License for more details.
Harald Welte2ca7c312009-12-23 22:44:04 +010018 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010019 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte2ca7c312009-12-23 22:44:04 +010021 *
22 */
23
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <errno.h>
28#include <string.h>
29#include <signal.h>
30#include <time.h>
31#include <sys/fcntl.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/ioctl.h>
35#include <arpa/inet.h>
36#include <netinet/in.h>
37
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +080038#define _GNU_SOURCE
39#include <getopt.h>
40
Harald Welte2ca7c312009-12-23 22:44:04 +010041#include <openbsc/gsm_data.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/select.h>
43#include <osmocom/gsm/tlv.h>
44#include <osmocom/core/msgb.h>
Harald Welte2ca7c312009-12-23 22:44:04 +010045#include <openbsc/debug.h>
46#include <openbsc/ipaccess.h>
Pablo Neira Ayusoda2f7692011-04-05 18:33:28 +020047#include <openbsc/socket.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010048#include <osmocom/core/talloc.h>
Harald Welte2ca7c312009-12-23 22:44:04 +010049
Harald Weltedc5062b2010-03-26 21:28:59 +080050static struct log_target *stderr_target;
Harald Welte2ca7c312009-12-23 22:44:04 +010051
52/* one instance of an ip.access protocol proxy */
53struct ipa_proxy {
54 /* socket where we listen for incoming OML from BTS */
55 struct bsc_fd oml_listen_fd;
56 /* socket where we listen for incoming RSL from BTS */
57 struct bsc_fd rsl_listen_fd;
58 /* list of BTS's (struct ipa_bts_conn */
59 struct llist_head bts_list;
60 /* the BSC reconnect timer */
61 struct timer_list reconn_timer;
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +080062 /* global GPRS NS data */
63 struct in_addr gprs_addr;
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +080064 struct in_addr listen_addr;
Harald Welte2ca7c312009-12-23 22:44:04 +010065};
66
67/* global pointer to the proxy structure */
68static struct ipa_proxy *ipp;
69
70struct ipa_proxy_conn {
71 struct bsc_fd fd;
72 struct llist_head tx_queue;
73 struct ipa_bts_conn *bts_conn;
74};
Harald Welte2ca7c312009-12-23 22:44:04 +010075#define MAX_TRX 4
76
77/* represents a particular BTS in our proxy */
78struct ipa_bts_conn {
79 /* list of BTS's (ipa_proxy->bts_list) */
80 struct llist_head list;
81 /* back pointer to the proxy which we belong to */
82 struct ipa_proxy *ipp;
83 /* the unit ID as determined by CCM */
84 struct {
85 u_int16_t site_id;
86 u_int16_t bts_id;
87 } unit_id;
88
89 /* incoming connections from BTS */
90 struct ipa_proxy_conn *oml_conn;
91 struct ipa_proxy_conn *rsl_conn[MAX_TRX];
92
93 /* outgoing connections to BSC */
94 struct ipa_proxy_conn *bsc_oml_conn;
95 struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX];
96
97 /* UDP sockets for BTS and BSC injection */
98 struct bsc_fd udp_bts_fd;
99 struct bsc_fd udp_bsc_fd;
100
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800101 /* NS data */
102 struct in_addr bts_addr;
103 struct bsc_fd gprs_ns_fd;
104 int gprs_local_port;
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +0800105 uint16_t gprs_orig_port;
106 uint32_t gprs_orig_ip;
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800107
Harald Welte2ca7c312009-12-23 22:44:04 +0100108 char *id_tags[0xff];
109 u_int8_t *id_resp;
110 unsigned int id_resp_len;
111};
112
113enum ipp_fd_type {
114 OML_FROM_BTS = 1,
115 RSL_FROM_BTS = 2,
116 OML_TO_BSC = 3,
117 RSL_TO_BSC = 4,
118 UDP_TO_BTS = 5,
119 UDP_TO_BSC = 6,
120};
121
122/* some of the code against we link from OpenBSC needs this */
123void *tall_bsc_ctx;
124
125static char *listen_ipaddr;
126static char *bsc_ipaddr;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800127static char *gprs_ns_ipaddr;
Harald Welte2ca7c312009-12-23 22:44:04 +0100128
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800129static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *);
130static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what);
131
Holger Hans Peter Freyther3dac8812010-06-09 14:39:22 +0800132#define PROXY_ALLOC_SIZE 1200
Harald Welte2ca7c312009-12-23 22:44:04 +0100133
Harald Welte2ca7c312009-12-23 22:44:04 +0100134static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
135 u_int16_t site_id,
136 u_int16_t bts_id)
137{
138 struct ipa_bts_conn *ipbc;
139
140 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
141 if (ipbc->unit_id.site_id == site_id &&
142 ipbc->unit_id.bts_id == bts_id)
143 return ipbc;
144 }
145
146 return NULL;
147}
148
149struct ipa_proxy_conn *alloc_conn(void)
150{
151 struct ipa_proxy_conn *ipc;
152
153 ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
154 if (!ipc)
155 return NULL;
156
157 INIT_LLIST_HEAD(&ipc->tx_queue);
158
159 return ipc;
160}
161
162static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
163{
164 unsigned int i, len;
165
166 for (i = 0; i <= 0xff; i++) {
167 if (!TLVP_PRESENT(tlvp, i))
168 continue;
169
170 len = TLVP_LEN(tlvp, i);
171#if 0
172 if (!ipbc->id_tags[i])
173 ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
174 else
175#endif
Harald Weltea16ef3d2009-12-23 23:35:51 +0100176 ipbc->id_tags[i] = talloc_realloc_size(ipbc,
Harald Welte2ca7c312009-12-23 22:44:04 +0100177 ipbc->id_tags[i], len);
178 if (!ipbc->id_tags[i])
179 return -ENOMEM;
180
181 memset(ipbc->id_tags[i], 0, len);
182 //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
183 }
184 return 0;
185}
186
187
188static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
189
190#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
191
192static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
193 struct ipa_bts_conn *ipbc, u_int8_t trx_id)
194{
195 if (ipbc)
Harald Weltedc5062b2010-03-26 21:28:59 +0800196 logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
Harald Welte2ca7c312009-12-23 22:44:04 +0100197 ipbc->unit_id.bts_id, trx_id);
198 else
Harald Weltedc5062b2010-03-26 21:28:59 +0800199 logp2(ss, lvl, file, line, 0, "unknown ");
Harald Welte2ca7c312009-12-23 22:44:04 +0100200}
201
Harald Welte2ca7c312009-12-23 22:44:04 +0100202static int handle_udp_read(struct bsc_fd *bfd)
203{
204 struct ipa_bts_conn *ipbc = bfd->data;
205 struct ipa_proxy_conn *other_conn = NULL;
206 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
207 struct ipaccess_head *hh;
208 int ret;
209
210 /* with UDP sockets, we cannot read partial packets but have to read
211 * all of it in one go */
212 hh = (struct ipaccess_head *) msg->data;
213 ret = recv(bfd->fd, msg->data, msg->data_len, 0);
214 if (ret < 0) {
Harald Weltefb339572009-12-24 13:35:18 +0100215 if (errno != EAGAIN)
216 LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +0100217 msgb_free(msg);
218 return ret;
219 }
220 if (ret == 0) {
221 DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
222 bsc_unregister_fd(bfd);
223 close(bfd->fd);
224 bfd->fd = -1;
225 msgb_free(msg);
226 return -EIO;
227 }
228 if (ret < sizeof(*hh)) {
229 DEBUGP(DINP, "could not even read header!?!\n");
230 msgb_free(msg);
231 return -EIO;
232 }
233 msgb_put(msg, ret);
234 msg->l2h = msg->data + sizeof(*hh);
235 DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len));
236
237 if (hh->len != msg->len - sizeof(*hh)) {
238 DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
239 msg->len, msg->len - 3, hh->len);
240 msgb_free(msg);
241 return -EIO;
242 }
243
244 switch (bfd->priv_nr & 0xff) {
245 case UDP_TO_BTS:
246 /* injection towards BTS */
247 switch (hh->proto) {
248 case IPAC_PROTO_RSL:
249 /* FIXME: what to do about TRX > 0 */
250 other_conn = ipbc->rsl_conn[0];
251 break;
252 default:
253 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
254 "OML FD\n", hh->proto);
255 /* fall through */
256 case IPAC_PROTO_IPACCESS:
257 case IPAC_PROTO_OML:
258 other_conn = ipbc->oml_conn;
259 break;
260 }
261 break;
262 case UDP_TO_BSC:
263 /* injection towards BSC */
264 switch (hh->proto) {
265 case IPAC_PROTO_RSL:
266 /* FIXME: what to do about TRX > 0 */
267 other_conn = ipbc->bsc_rsl_conn[0];
268 break;
269 default:
270 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
271 "OML FD\n", hh->proto);
272 case IPAC_PROTO_IPACCESS:
273 case IPAC_PROTO_OML:
274 other_conn = ipbc->bsc_oml_conn;
275 break;
276 }
277 break;
278 default:
279 DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
280 break;
281 }
282
283 if (other_conn) {
284 /* enqueue the message for TX on the respective FD */
285 msgb_enqueue(&other_conn->tx_queue, msg);
286 other_conn->fd.when |= BSC_FD_WRITE;
287 } else
288 msgb_free(msg);
289
290 return 0;
291}
292
293static int handle_udp_write(struct bsc_fd *bfd)
294{
295 /* not implemented yet */
296 bfd->when &= ~BSC_FD_WRITE;
297
298 return -EIO;
299}
300
301/* callback from select.c in case one of the fd's can be read/written */
302static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what)
303{
304 int rc = 0;
305
306 if (what & BSC_FD_READ)
307 rc = handle_udp_read(bfd);
308 if (what & BSC_FD_WRITE)
309 rc = handle_udp_write(bfd);
310
311 return rc;
312}
313
314
315static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd,
316 u_int16_t site_id, u_int16_t bts_id,
317 u_int16_t trx_id, struct tlv_parsed *tlvp,
318 struct msgb *msg)
319{
320 struct ipa_bts_conn *ipbc;
321 u_int16_t udp_port;
322 int ret = 0;
323 struct sockaddr_in sin;
324
325 memset(&sin, 0, sizeof(sin));
326 sin.sin_family = AF_INET;
327 inet_aton(bsc_ipaddr, &sin.sin_addr);
328
329 DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
330 site_id, bts_id, trx_id);
331
332 /* OML needs to be established before RSL */
333 if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
334 DEBUGPC(DINP, "Not a OML connection ?!?\n");
335 return -EIO;
336 }
337
338 /* allocate new BTS connection data structure */
339 ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
340 if (!ipbc) {
341 ret = -ENOMEM;
342 goto err_out;
343 }
344
345 DEBUGPC(DINP, "Created BTS Conn data structure\n");
346 ipbc->ipp = ipp;
347 ipbc->unit_id.site_id = site_id;
348 ipbc->unit_id.bts_id = bts_id;
349 ipbc->oml_conn = ipc;
350 ipc->bts_conn = ipbc;
351
352 /* store the content of the ID TAGS for later reference */
353 store_idtags(ipbc, tlvp);
354 ipbc->id_resp_len = msg->len;
355 ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
356 memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
357
358 /* Create OML TCP connection towards BSC */
Harald Welte87ed5cd2009-12-23 22:47:53 +0100359 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte2ca7c312009-12-23 22:44:04 +0100360 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
361 if (!ipbc->bsc_oml_conn) {
362 ret = -EIO;
363 goto err_bsc_conn;
364 }
365
366 DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
367 site_id, bts_id, trx_id);
368
369 /* Create UDP socket for BTS packet injection */
370 udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoda2f7692011-04-05 18:33:28 +0200371 ret = make_sock(&ipbc->udp_bts_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte2ca7c312009-12-23 22:44:04 +0100372 UDP_TO_BTS, udp_fd_cb, ipbc);
373 if (ret < 0)
374 goto err_udp_bts;
375 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
376 "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
377
378 /* Create UDP socket for BSC packet injection */
379 udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoda2f7692011-04-05 18:33:28 +0200380 ret = make_sock(&ipbc->udp_bsc_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte2ca7c312009-12-23 22:44:04 +0100381 UDP_TO_BSC, udp_fd_cb, ipbc);
382 if (ret < 0)
383 goto err_udp_bsc;
384 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
385 "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800386
387
388 /* GPRS NS related code */
389 if (gprs_ns_ipaddr) {
390 struct sockaddr_in sock;
391 socklen_t len = sizeof(sock);
392 ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc);
393 if (ret < 0) {
394 LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
395 goto err_udp_bsc;
396 }
397
398 ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
399 ipbc->gprs_local_port = ntohs(sock.sin_port);
400 LOGP(DINP, LOGL_NOTICE,
401 "Created GPRS NS Socket. Listening on: %s:%d\n",
402 inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
403
404 ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
405 ipbc->bts_addr = sock.sin_addr;
406 }
407
Harald Welte2ca7c312009-12-23 22:44:04 +0100408 llist_add(&ipbc->list, &ipp->bts_list);
409
410 return 0;
411
412err_udp_bsc:
413 bsc_unregister_fd(&ipbc->udp_bts_fd);
414err_udp_bts:
415 bsc_unregister_fd(&ipbc->bsc_oml_conn->fd);
416 close(ipbc->bsc_oml_conn->fd.fd);
417 talloc_free(ipbc->bsc_oml_conn);
418 ipbc->bsc_oml_conn = NULL;
419err_bsc_conn:
420 talloc_free(ipbc->id_resp);
421 talloc_free(ipbc);
422#if 0
423 bsc_unregister_fd(bfd);
424 close(bfd->fd);
425 talloc_free(bfd);
426#endif
427err_out:
428 return ret;
429}
430
431static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
432 struct bsc_fd *bfd)
433{
434 struct tlv_parsed tlvp;
435 u_int8_t msg_type = *(msg->l2h);
436 u_int16_t site_id, bts_id, trx_id;
437 struct ipa_bts_conn *ipbc;
438 int ret = 0;
439
440 switch (msg_type) {
441 case IPAC_MSGT_PING:
Pablo Neira Ayuso22f58a92011-04-07 14:15:06 +0200442 ret = ipaccess_send_pong(bfd->fd);
Harald Welte2ca7c312009-12-23 22:44:04 +0100443 break;
444 case IPAC_MSGT_PONG:
445 DEBUGP(DMI, "PONG!\n");
446 break;
447 case IPAC_MSGT_ID_RESP:
448 DEBUGP(DMI, "ID_RESP ");
449 /* parse tags, search for Unit ID */
Pablo Neira Ayuso625295b2011-04-07 14:15:16 +0200450 ipaccess_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
451 msgb_l2len(msg)-2);
Harald Welte2ca7c312009-12-23 22:44:04 +0100452 DEBUGP(DMI, "\n");
453
454 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
455 LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
456 return -EIO;
457 }
458
459 /* lookup BTS, create sign_link, ... */
Holger Hans Peter Freyther82ae7162010-03-30 15:20:46 +0200460 site_id = bts_id = trx_id = 0;
Pablo Neira Ayusoc281b4e2011-04-07 14:15:20 +0200461 ipaccess_parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
462 &site_id, &bts_id, &trx_id);
Harald Welte2ca7c312009-12-23 22:44:04 +0100463 ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
464 if (!ipbc) {
465 /* We have not found an ipbc (per-bts proxy instance)
466 * for this BTS yet. The first connection of a new BTS must
467 * be a OML connection. We allocate the associated data structures,
468 * and try to connect to the remote end */
469
470 return ipbc_alloc_connect(ipc, bfd, site_id, bts_id,
471 trx_id, &tlvp, msg);
472 /* if this fails, the caller will clean up bfd */
473 } else {
474 struct sockaddr_in sin;
475 memset(&sin, 0, sizeof(sin));
476 sin.sin_family = AF_INET;
477 inet_aton(bsc_ipaddr, &sin.sin_addr);
478
479 DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
480 site_id, bts_id, trx_id);
481
482 if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
483 LOGP(DINP, LOGL_ERROR, "Second OML connection from "
484 "same BTS ?!?\n");
485 return 0;
486 }
487
488 if (trx_id > MAX_TRX) {
489 LOGP(DINP, LOGL_ERROR, "We don't support more "
490 "than %u TRX\n", MAX_TRX);
491 return -EINVAL;
492 }
493
494 ipc->bts_conn = ipbc;
495 /* store TRX number in higher 8 bit of the bfd private number */
496 bfd->priv_nr |= trx_id << 8;
497 ipbc->rsl_conn[trx_id] = ipc;
498
499 /* Create RSL TCP connection towards BSC */
Harald Welte87ed5cd2009-12-23 22:47:53 +0100500 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte2ca7c312009-12-23 22:44:04 +0100501 ipbc->bsc_rsl_conn[trx_id] =
502 connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
503 if (!ipbc->bsc_oml_conn)
504 return -EIO;
505 DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
506 site_id, bts_id, trx_id);
507 }
508 break;
509 case IPAC_MSGT_ID_GET:
510 DEBUGP(DMI, "ID_GET\n");
511 if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
512 (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
513 DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
514 return -EIO;
515 }
516 ipbc = ipc->bts_conn;
517 if (!ipbc) {
518 DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
519 return -EIO;
520 }
521 ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
522 break;
523 case IPAC_MSGT_ID_ACK:
524 DEBUGP(DMI, "ID_ACK? -> ACK!\n");
Pablo Neira Ayuso22f58a92011-04-07 14:15:06 +0200525 ret = ipaccess_send_id_ack(bfd->fd);
Harald Welte2ca7c312009-12-23 22:44:04 +0100526 break;
Holger Hans Peter Freyther0897dad2010-06-09 17:38:59 +0800527 default:
528 LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
529 return 1;
530 break;
Harald Welte2ca7c312009-12-23 22:44:04 +0100531 }
532 return 0;
533}
534
Pablo Neira Ayuso22f58a92011-04-07 14:15:06 +0200535struct msgb *ipaccess_proxy_read_msg(struct bsc_fd *bfd, int *error)
Harald Welte2ca7c312009-12-23 22:44:04 +0100536{
537 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
538 struct ipaccess_head *hh;
539 int len, ret = 0;
540
541 if (!msg) {
542 *error = -ENOMEM;
543 return NULL;
544 }
545
546 /* first read our 3-byte header */
547 hh = (struct ipaccess_head *) msg->data;
548 ret = recv(bfd->fd, msg->data, 3, 0);
549 if (ret < 0) {
Harald Weltefb339572009-12-24 13:35:18 +0100550 if (errno != EAGAIN)
Harald Welteda956932009-12-24 12:49:43 +0100551 LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +0100552 msgb_free(msg);
553 *error = ret;
554 return NULL;
555 } else if (ret == 0) {
556 msgb_free(msg);
557 *error = ret;
558 return NULL;
559 }
560
561 msgb_put(msg, ret);
562
563 /* then read te length as specified in header */
564 msg->l2h = msg->data + sizeof(*hh);
565 len = ntohs(hh->len);
566 ret = recv(bfd->fd, msg->l2h, len, 0);
567 if (ret < len) {
568 LOGP(DINP, LOGL_ERROR, "short read!\n");
569 msgb_free(msg);
570 *error = -EIO;
571 return NULL;
572 }
573 msgb_put(msg, ret);
574
575 return msg;
576}
577
578static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
579 unsigned int priv_nr)
580{
581 struct ipa_proxy_conn *bsc_conn;
582 unsigned int trx_id = priv_nr >> 8;
583
584 switch (priv_nr & 0xff) {
585 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
586 bsc_conn = ipbc->bsc_oml_conn;
587 break;
588 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
589 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
590 break;
591 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
592 bsc_conn = ipbc->oml_conn;
593 break;
594 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
595 bsc_conn = ipbc->rsl_conn[trx_id];
596 break;
597 default:
598 bsc_conn = NULL;
599 break;
600 }
601 return bsc_conn;
602}
603
604static void reconn_tmr_cb(void *data)
605{
606 struct ipa_proxy *ipp = data;
607 struct ipa_bts_conn *ipbc;
608 struct sockaddr_in sin;
609 int i;
610
611 DEBUGP(DINP, "Running reconnect timer\n");
612
613 memset(&sin, 0, sizeof(sin));
614 sin.sin_family = AF_INET;
615 inet_aton(bsc_ipaddr, &sin.sin_addr);
616
617 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
618 /* if OML to BSC is dead, try to restore it */
619 if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
Harald Welte87ed5cd2009-12-23 22:47:53 +0100620 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte2ca7c312009-12-23 22:44:04 +0100621 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
622 LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
623 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
624 if (!ipbc->bsc_oml_conn)
625 goto reschedule;
626 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
627 LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
628 }
629 /* if we (still) don't have a OML connection, skip RSL */
630 if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
631 continue;
632
633 for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
634 unsigned int priv_nr;
635 /* don't establish RSL links which we don't have */
636 if (!ipbc->rsl_conn[i])
637 continue;
638 if (ipbc->bsc_rsl_conn[i])
639 continue;
640 priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
641 priv_nr &= ~0xff;
642 priv_nr |= RSL_TO_BSC;
Harald Welte87ed5cd2009-12-23 22:47:53 +0100643 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte2ca7c312009-12-23 22:44:04 +0100644 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
645 LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
646 ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
647 if (!ipbc->bsc_rsl_conn)
648 goto reschedule;
649 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
650 LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
651 }
652 }
653 return;
654
655reschedule:
656 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
657}
658
659static void handle_dead_socket(struct bsc_fd *bfd)
660{
661 struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
662 struct ipa_proxy_conn *bsc_conn; /* remote conn */
663 struct ipa_bts_conn *ipbc = ipc->bts_conn;
664 unsigned int trx_id = bfd->priv_nr >> 8;
665 struct msgb *msg, *msg2;
666
667 bsc_unregister_fd(bfd);
668 close(bfd->fd);
669 bfd->fd = -1;
670
671 /* FIXME: clear tx_queue, remove all references, etc. */
672 llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
673 msgb_free(msg);
674
675 switch (bfd->priv_nr & 0xff) {
676 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
Pablo Neira Ayuso3c409c22011-03-27 21:31:48 +0200677 /* The BTS started a connection with us but we got no
678 * IPAC_MSGT_ID_RESP message yet, in that scenario we did not
679 * allocate the ipa_bts_conn structure. */
680 if (ipbc == NULL)
681 break;
Harald Welte2ca7c312009-12-23 22:44:04 +0100682 ipbc->oml_conn = NULL;
683 bsc_conn = ipbc->bsc_oml_conn;
684 /* close the connection to the BSC */
685 bsc_unregister_fd(&bsc_conn->fd);
686 close(bsc_conn->fd.fd);
687 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
688 msgb_free(msg);
689 talloc_free(bsc_conn);
690 ipbc->bsc_oml_conn = NULL;
691 /* FIXME: do we need to delete the entire ipbc ? */
692 break;
693 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
694 ipbc->rsl_conn[trx_id] = NULL;
695 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
696 /* close the connection to the BSC */
697 bsc_unregister_fd(&bsc_conn->fd);
698 close(bsc_conn->fd.fd);
699 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
700 msgb_free(msg);
701 talloc_free(bsc_conn);
702 ipbc->bsc_rsl_conn[trx_id] = NULL;
703 break;
704 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
705 ipbc->bsc_oml_conn = NULL;
706 bsc_conn = ipbc->oml_conn;
707 /* start reconnect timer */
708 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
709 break;
710 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
711 ipbc->bsc_rsl_conn[trx_id] = NULL;
712 bsc_conn = ipbc->rsl_conn[trx_id];
713 /* start reconnect timer */
714 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
715 break;
716 default:
717 bsc_conn = NULL;
718 break;
719 }
720
721 talloc_free(ipc);
722}
723
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +0800724static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg)
725{
726 uint8_t *nsvci;
727
728 if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC)
729 return;
730
731 if (msgb_l2len(msg) != 39)
732 return;
733
734 /*
735 * Check if this is a IPA Set Attribute or IPA Set Attribute ACK
736 * and if the FOM Class is GPRS NSVC0 and then we will patch it.
737 *
738 * The patch assumes the message looks like the one from the trace
739 * but we only match messages with a specific size anyway... So
740 * this hack should work just fine.
741 */
742
743 if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
744 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
745 msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +0800746 nsvci = &msg->l2h[23];
747 ipbc->gprs_orig_port = *(u_int16_t *)(nsvci+8);
748 ipbc->gprs_orig_ip = *(u_int32_t *)(nsvci+10);
749 *(u_int16_t *)(nsvci+8) = htons(ipbc->gprs_local_port);
750 *(u_int32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr;
751 } else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
752 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
753 msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +0800754 nsvci = &msg->l2h[23];
755 *(u_int16_t *)(nsvci+8) = ipbc->gprs_orig_port;
756 *(u_int32_t *)(nsvci+10) = ipbc->gprs_orig_ip;
757 }
758}
759
Harald Welte2ca7c312009-12-23 22:44:04 +0100760static int handle_tcp_read(struct bsc_fd *bfd)
761{
762 struct ipa_proxy_conn *ipc = bfd->data;
763 struct ipa_bts_conn *ipbc = ipc->bts_conn;
764 struct ipa_proxy_conn *bsc_conn;
Harald Weltea16ef3d2009-12-23 23:35:51 +0100765 struct msgb *msg;
Harald Welte2ca7c312009-12-23 22:44:04 +0100766 struct ipaccess_head *hh;
767 int ret = 0;
768 char *btsbsc;
769
Harald Welte2ca7c312009-12-23 22:44:04 +0100770 if ((bfd->priv_nr & 0xff) <= 2)
771 btsbsc = "BTS";
772 else
773 btsbsc = "BSC";
774
Pablo Neira Ayuso22f58a92011-04-07 14:15:06 +0200775 msg = ipaccess_proxy_read_msg(bfd, &ret);
Harald Welte2ca7c312009-12-23 22:44:04 +0100776 if (!msg) {
777 if (ret == 0) {
778 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
779 LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
780 "dead socket\n", btsbsc);
781 handle_dead_socket(bfd);
782 }
783 return ret;
784 }
785
786 msgb_put(msg, ret);
787 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
788 DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
789
790 hh = (struct ipaccess_head *) msg->data;
791 if (hh->proto == IPAC_PROTO_IPACCESS) {
792 ret = ipaccess_rcvmsg(ipc, msg, bfd);
793 if (ret < 0) {
794 bsc_unregister_fd(bfd);
795 close(bfd->fd);
796 bfd->fd = -1;
797 talloc_free(bfd);
Holger Hans Peter Freyther0897dad2010-06-09 17:38:59 +0800798 msgb_free(msg);
799 return ret;
800 } else if (ret == 0) {
801 /* we do not forward parts of the CCM protocol
802 * through the proxy but rather terminate it ourselves. */
803 msgb_free(msg);
804 return ret;
Harald Welte2ca7c312009-12-23 22:44:04 +0100805 }
Harald Welte2ca7c312009-12-23 22:44:04 +0100806 }
807
808 if (!ipbc) {
809 LOGP(DINP, LOGL_ERROR,
810 "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
811 msgb_free(msg);
812 return -EIO;
813 }
814
815 bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
816 if (bsc_conn) {
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +0800817 if (gprs_ns_ipaddr)
818 patch_gprs_msg(ipbc, bfd->priv_nr, msg);
Harald Welte2ca7c312009-12-23 22:44:04 +0100819 /* enqueue packet towards BSC */
820 msgb_enqueue(&bsc_conn->tx_queue, msg);
821 /* mark respective filedescriptor as 'we want to write' */
822 bsc_conn->fd.when |= BSC_FD_WRITE;
823 } else {
824 logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
825 LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
826 "since remote connection is dead\n", btsbsc);
827 msgb_free(msg);
828 }
829
830 return ret;
831}
832
833/* a TCP socket is ready to be written to */
834static int handle_tcp_write(struct bsc_fd *bfd)
835{
836 struct ipa_proxy_conn *ipc = bfd->data;
837 struct ipa_bts_conn *ipbc = ipc->bts_conn;
838 struct llist_head *lh;
839 struct msgb *msg;
840 char *btsbsc;
841 int ret;
842
843 if ((bfd->priv_nr & 0xff) <= 2)
844 btsbsc = "BTS";
845 else
846 btsbsc = "BSC";
847
848
849 /* get the next msg for this timeslot */
850 if (llist_empty(&ipc->tx_queue)) {
851 bfd->when &= ~BSC_FD_WRITE;
852 return 0;
853 }
854 lh = ipc->tx_queue.next;
855 llist_del(lh);
856 msg = llist_entry(lh, struct msgb, list);
857
858 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
859 DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
860 hexdump(msg->data, msg->len));
861
862 ret = send(bfd->fd, msg->data, msg->len, 0);
863 msgb_free(msg);
864
865 if (ret == 0) {
866 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
867 LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
868 handle_dead_socket(bfd);
869 }
870
871 return ret;
872}
873
874/* callback from select.c in case one of the fd's can be read/written */
875static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
876{
877 int rc = 0;
878
879 if (what & BSC_FD_READ) {
880 rc = handle_tcp_read(bfd);
881 if (rc < 0)
882 return rc;
883 }
884 if (what & BSC_FD_WRITE)
885 rc = handle_tcp_write(bfd);
886
887 return rc;
888}
889
890/* callback of the listening filedescriptor */
891static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
892{
893 int ret;
894 struct ipa_proxy_conn *ipc;
895 struct bsc_fd *bfd;
896 struct sockaddr_in sa;
897 socklen_t sa_len = sizeof(sa);
898
899 if (!(what & BSC_FD_READ))
900 return 0;
901
902 ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
903 if (ret < 0) {
904 perror("accept");
905 return ret;
906 }
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200907 DEBUGP(DINP, "accept()ed new %s link from %s\n",
Harald Welte2ca7c312009-12-23 22:44:04 +0100908 (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
909 inet_ntoa(sa.sin_addr));
910
911 ipc = alloc_conn();
912 if (!ipc) {
913 close(ret);
914 return -ENOMEM;
915 }
916
917 bfd = &ipc->fd;
918 bfd->fd = ret;
919 bfd->data = ipc;
920 bfd->priv_nr = listen_bfd->priv_nr;
921 bfd->cb = ipaccess_fd_cb;
922 bfd->when = BSC_FD_READ;
923 ret = bsc_register_fd(bfd);
924 if (ret < 0) {
925 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
926 close(bfd->fd);
927 talloc_free(ipc);
928 return ret;
929 }
930
931 /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
Pablo Neira Ayuso22f58a92011-04-07 14:15:06 +0200932 ret = ipaccess_send_id_req(bfd->fd);
Harald Welte2ca7c312009-12-23 22:44:04 +0100933
934 return 0;
935}
936
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800937static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
938{
939 int ret;
940 struct sockaddr_in addr;
941 socklen_t len = sizeof(addr);
942 memset(&addr, 0, sizeof(addr));
943
944 addr.sin_family = AF_INET;
Holger Hans Peter Freyther21e1c0d2010-06-10 15:56:26 +0800945 addr.sin_port = htons(port);
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800946 addr.sin_addr = ip;
947
948 ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
949 if (ret < 0) {
950 LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
951 }
952}
953
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800954static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
955{
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800956 struct ipa_bts_conn *bts;
957 char buf[4096];
958 int ret;
959 struct sockaddr_in sock;
960 socklen_t len = sizeof(sock);
961
962 /* 1. get the data... */
963 ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
964 if (ret < 0) {
965 LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
966 return -1;
967 }
968
969 bts = bfd->data;
970
971 /* 2. figure out where to send it to */
972 if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
973 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
974 send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
975 } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
976 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
977 send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
Holger Hans Peter Freyther21e1c0d2010-06-10 15:56:26 +0800978 } else {
979 LOGP(DINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800980 }
981
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800982 return 0;
983}
984
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800985static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *data)
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800986{
987 struct sockaddr_in addr;
988 int ret;
989
990 bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
991 bfd->cb = cb;
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800992 bfd->data = data;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800993 bfd->when = BSC_FD_READ;
994
995 memset(&addr, 0, sizeof(addr));
996 addr.sin_family = AF_INET;
997 addr.sin_port = 0;
998 inet_aton(listen_ipaddr, &addr.sin_addr);
999
1000 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1001 if (ret < 0) {
1002 LOGP(DINP, LOGL_ERROR,
1003 "Could not bind n socket for IP %s with error: %s.\n",
1004 listen_ipaddr, strerror(errno));
1005 return -EIO;
1006 }
1007
1008 ret = bsc_register_fd(bfd);
1009 if (ret < 0) {
1010 perror("register_listen_fd");
1011 return ret;
1012 }
1013 return 0;
1014}
1015
Harald Welte2ca7c312009-12-23 22:44:04 +01001016/* Actively connect to a BSC. */
1017static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
1018{
1019 struct ipa_proxy_conn *ipc;
1020 struct bsc_fd *bfd;
1021 int ret, on = 1;
1022
1023 ipc = alloc_conn();
1024 if (!ipc)
1025 return NULL;
1026
1027 ipc->bts_conn = data;
1028
1029 bfd = &ipc->fd;
1030 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1031 bfd->cb = ipaccess_fd_cb;
1032 bfd->when = BSC_FD_READ | BSC_FD_WRITE;
1033 bfd->data = ipc;
1034 bfd->priv_nr = priv_nr;
1035
1036 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1037
1038 ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
1039 if (ret < 0) {
Holger Hans Peter Freyther6cb9b232010-06-09 15:15:11 +08001040 LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
1041 inet_ntoa(sa->sin_addr));
Harald Welte2ca7c312009-12-23 22:44:04 +01001042 close(bfd->fd);
1043 talloc_free(ipc);
1044 return NULL;
1045 }
1046
1047 /* pre-fill tx_queue with identity request */
1048 ret = bsc_register_fd(bfd);
1049 if (ret < 0) {
1050 close(bfd->fd);
1051 talloc_free(ipc);
1052 return NULL;
1053 }
1054
1055 return ipc;
1056}
1057
1058static int ipaccess_proxy_setup(void)
1059{
1060 int ret;
1061
1062 ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
1063 if (!ipp)
1064 return -ENOMEM;
1065 INIT_LLIST_HEAD(&ipp->bts_list);
1066 ipp->reconn_timer.cb = reconn_tmr_cb;
1067 ipp->reconn_timer.data = ipp;
1068
1069 /* Listen for OML connections */
Pablo Neira Ayuso3ab864a2011-04-07 14:15:02 +02001070 ret = make_sock(&ipp->oml_listen_fd, IPPROTO_TCP, INADDR_ANY,
1071 IPA_TCP_PORT_OML, OML_FROM_BTS, listen_fd_cb, NULL);
Harald Welte2ca7c312009-12-23 22:44:04 +01001072 if (ret < 0)
1073 return ret;
1074
1075 /* Listen for RSL connections */
Pablo Neira Ayuso3ab864a2011-04-07 14:15:02 +02001076 ret = make_sock(&ipp->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY,
1077 IPA_TCP_PORT_RSL, RSL_FROM_BTS, listen_fd_cb, NULL);
Harald Welte2ca7c312009-12-23 22:44:04 +01001078
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001079 if (ret < 0)
1080 return ret;
1081
1082 /* Connect the GPRS NS Socket */
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +08001083 if (gprs_ns_ipaddr) {
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001084 inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
Holger Hans Peter Freyther4fe22cc2010-06-10 15:57:08 +08001085 inet_aton(listen_ipaddr, &ipp->listen_addr);
1086 }
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001087
Harald Welte2ca7c312009-12-23 22:44:04 +01001088 return ret;
1089}
1090
1091static void signal_handler(int signal)
1092{
1093 fprintf(stdout, "signal %u received\n", signal);
1094
1095 switch (signal) {
1096 case SIGABRT:
1097 /* in case of abort, we want to obtain a talloc report
1098 * and then return to the caller, who will abort the process */
1099 case SIGUSR1:
1100 talloc_report_full(tall_bsc_ctx, stderr);
1101 break;
1102 default:
1103 break;
1104 }
1105}
1106
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001107static void print_help()
1108{
1109 printf(" ipaccess-proxy is a proxy BTS.\n");
1110 printf(" -h --help. This help text.\n");
1111 printf(" -l --listen IP. The ip to listen to.\n");
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001112 printf(" -b --bsc IP. The BSC IP address.\n");
1113 printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
1114 printf("\n");
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001115 printf(" -s --disable-color. Disable the color inside the logging message.\n");
1116 printf(" -e --log-level number. Set the global loglevel.\n");
1117 printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
1118 printf(" -V --version. Print the version of OpenBSC.\n");
1119}
1120
1121static void print_usage()
1122{
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001123 printf("Usage: ipaccess-proxy [options]\n");
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001124}
1125
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001126enum {
1127 IPA_PROXY_OPT_LISTEN_NONE = 0,
1128 IPA_PROXY_OPT_LISTEN_IP = (1 << 0),
1129 IPA_PROXY_OPT_BSC_IP = (1 << 1),
1130};
1131
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001132static void handle_options(int argc, char** argv)
1133{
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001134 int options_mask = 0;
1135
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001136 while (1) {
1137 int option_index = 0, c;
1138 static struct option long_options[] = {
1139 {"help", 0, 0, 'h'},
1140 {"disable-color", 0, 0, 's'},
1141 {"timestamp", 0, 0, 'T'},
1142 {"log-level", 1, 0, 'e'},
1143 {"listen", 1, 0, 'l'},
1144 {"bsc", 1, 0, 'b'},
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001145 {"udp", 1, 0, 'u'},
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001146 {0, 0, 0, 0}
1147 };
1148
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001149 c = getopt_long(argc, argv, "hsTe:l:b:g:",
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001150 long_options, &option_index);
1151 if (c == -1)
1152 break;
1153
1154 switch (c) {
1155 case 'h':
1156 print_usage();
1157 print_help();
1158 exit(0);
1159 case 'l':
1160 listen_ipaddr = optarg;
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001161 options_mask |= IPA_PROXY_OPT_LISTEN_IP;
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001162 break;
1163 case 'b':
1164 bsc_ipaddr = optarg;
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001165 options_mask |= IPA_PROXY_OPT_BSC_IP;
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001166 break;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001167 case 'g':
1168 gprs_ns_ipaddr = optarg;
1169 break;
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001170 case 's':
1171 log_set_use_color(stderr_target, 0);
1172 break;
1173 case 'T':
1174 log_set_print_timestamp(stderr_target, 1);
1175 break;
1176 case 'e':
1177 log_set_log_level(stderr_target, atoi(optarg));
1178 break;
1179 default:
1180 /* ignore */
1181 break;
1182 }
1183 }
Pablo Neira Ayuso9f1294d2011-04-07 18:47:39 +02001184 if ((options_mask & (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP))
1185 != (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP)) {
1186 printf("ERROR: You have to specify `--listen' and `--bsc' "
1187 "options at least.\n");
1188 print_usage();
1189 print_help();
1190 exit(EXIT_FAILURE);
1191 }
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001192}
1193
Harald Welte2ca7c312009-12-23 22:44:04 +01001194int main(int argc, char **argv)
1195{
1196 int rc;
1197
Harald Welte2ca7c312009-12-23 22:44:04 +01001198 tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
1199
Harald Weltedc5062b2010-03-26 21:28:59 +08001200 log_init(&log_info);
1201 stderr_target = log_target_create_stderr();
1202 log_add_target(stderr_target);
1203 log_set_all_filter(stderr_target, 1);
1204 log_parse_category_mask(stderr_target, "DINP:DMI");
Harald Welte2ca7c312009-12-23 22:44:04 +01001205
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001206 handle_options(argc, argv);
1207
Harald Welte2ca7c312009-12-23 22:44:04 +01001208 rc = ipaccess_proxy_setup();
1209 if (rc < 0)
1210 exit(1);
1211
1212 signal(SIGUSR1, &signal_handler);
1213 signal(SIGABRT, &signal_handler);
1214
1215 while (1) {
1216 bsc_select_main(0);
1217 }
1218}