blob: 56e910111ae0cb1a7e042c6c527a819c88c20fca [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 Freyther1a0c2b72010-06-09 14:59:09 +08004 * (C) 2010 by On Waves
5 * (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
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (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
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <stdio.h>
26#include <unistd.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <string.h>
30#include <signal.h>
31#include <time.h>
32#include <sys/fcntl.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/ioctl.h>
36#include <arpa/inet.h>
37#include <netinet/in.h>
38
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +080039#define _GNU_SOURCE
40#include <getopt.h>
41
Harald Welte2ca7c312009-12-23 22:44:04 +010042#include <openbsc/gsm_data.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010043#include <osmocore/select.h>
44#include <osmocore/tlv.h>
45#include <osmocore/msgb.h>
Harald Welte2ca7c312009-12-23 22:44:04 +010046#include <openbsc/debug.h>
47#include <openbsc/ipaccess.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010048#include <osmocore/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;
Harald Welte2ca7c312009-12-23 22:44:04 +010064};
65
66/* global pointer to the proxy structure */
67static struct ipa_proxy *ipp;
68
69struct ipa_proxy_conn {
70 struct bsc_fd fd;
71 struct llist_head tx_queue;
72 struct ipa_bts_conn *bts_conn;
73};
Harald Welte2ca7c312009-12-23 22:44:04 +010074#define MAX_TRX 4
75
76/* represents a particular BTS in our proxy */
77struct ipa_bts_conn {
78 /* list of BTS's (ipa_proxy->bts_list) */
79 struct llist_head list;
80 /* back pointer to the proxy which we belong to */
81 struct ipa_proxy *ipp;
82 /* the unit ID as determined by CCM */
83 struct {
84 u_int16_t site_id;
85 u_int16_t bts_id;
86 } unit_id;
87
88 /* incoming connections from BTS */
89 struct ipa_proxy_conn *oml_conn;
90 struct ipa_proxy_conn *rsl_conn[MAX_TRX];
91
92 /* outgoing connections to BSC */
93 struct ipa_proxy_conn *bsc_oml_conn;
94 struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX];
95
96 /* UDP sockets for BTS and BSC injection */
97 struct bsc_fd udp_bts_fd;
98 struct bsc_fd udp_bsc_fd;
99
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800100 /* NS data */
101 struct in_addr bts_addr;
102 struct bsc_fd gprs_ns_fd;
103 int gprs_local_port;
104
Harald Welte2ca7c312009-12-23 22:44:04 +0100105 char *id_tags[0xff];
106 u_int8_t *id_resp;
107 unsigned int id_resp_len;
108};
109
110enum ipp_fd_type {
111 OML_FROM_BTS = 1,
112 RSL_FROM_BTS = 2,
113 OML_TO_BSC = 3,
114 RSL_TO_BSC = 4,
115 UDP_TO_BTS = 5,
116 UDP_TO_BSC = 6,
117};
118
119/* some of the code against we link from OpenBSC needs this */
120void *tall_bsc_ctx;
121
122static char *listen_ipaddr;
123static char *bsc_ipaddr;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +0800124static char *gprs_ns_ipaddr;
Harald Welte2ca7c312009-12-23 22:44:04 +0100125
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800126static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *);
127static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what);
128
Holger Hans Peter Freyther3dac8812010-06-09 14:39:22 +0800129#define PROXY_ALLOC_SIZE 1200
Harald Welte2ca7c312009-12-23 22:44:04 +0100130
131static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
132static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
133static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
134 0x01, IPAC_IDTAG_UNIT,
135 0x01, IPAC_IDTAG_MACADDR,
136 0x01, IPAC_IDTAG_LOCATION1,
137 0x01, IPAC_IDTAG_LOCATION2,
138 0x01, IPAC_IDTAG_EQUIPVERS,
139 0x01, IPAC_IDTAG_SWVERSION,
140 0x01, IPAC_IDTAG_UNITNAME,
141 0x01, IPAC_IDTAG_SERNR,
142 };
143
144static const char *idtag_names[] = {
145 [IPAC_IDTAG_SERNR] = "Serial_Number",
146 [IPAC_IDTAG_UNITNAME] = "Unit_Name",
147 [IPAC_IDTAG_LOCATION1] = "Location_1",
148 [IPAC_IDTAG_LOCATION2] = "Location_2",
149 [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
150 [IPAC_IDTAG_SWVERSION] = "Software_Version",
151 [IPAC_IDTAG_IPADDR] = "IP_Address",
152 [IPAC_IDTAG_MACADDR] = "MAC_Address",
153 [IPAC_IDTAG_UNIT] = "Unit_ID",
154};
155
156static const char *ipac_idtag_name(int tag)
157{
158 if (tag >= ARRAY_SIZE(idtag_names))
159 return "unknown";
160
161 return idtag_names[tag];
162}
163
164static int ipac_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
165{
166 u_int8_t t_len;
167 u_int8_t t_tag;
168 u_int8_t *cur = buf;
169
170 while (cur < buf + len) {
171 t_len = *cur++;
172 t_tag = *cur++;
173
174 DEBUGPC(DMI, "%s='%s' ", ipac_idtag_name(t_tag), cur);
175
176 dec->lv[t_tag].len = t_len;
177 dec->lv[t_tag].val = cur;
178
179 cur += t_len;
180 }
181 return 0;
182}
183
184static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
185 u_int16_t *trx_id)
186{
187 unsigned long ul;
188 char *endptr;
189 const char *nptr;
190
191 nptr = str;
192 ul = strtoul(nptr, &endptr, 10);
193 if (endptr <= nptr)
194 return -EINVAL;
195 if (site_id)
196 *site_id = ul & 0xffff;
197
198 if (*endptr++ != '/')
199 return -EINVAL;
200
201 nptr = endptr;
202 ul = strtoul(nptr, &endptr, 10);
203 if (endptr <= nptr)
204 return -EINVAL;
205 if (bts_id)
206 *bts_id = ul & 0xffff;
207
208 if (*endptr++ != '/')
209 return -EINVAL;
210
211 nptr = endptr;
212 ul = strtoul(nptr, &endptr, 10);
213 if (endptr <= nptr)
214 return -EINVAL;
215 if (trx_id)
216 *trx_id = ul & 0xffff;
217
218 return 0;
219}
220
221static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
222 u_int16_t site_id,
223 u_int16_t bts_id)
224{
225 struct ipa_bts_conn *ipbc;
226
227 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
228 if (ipbc->unit_id.site_id == site_id &&
229 ipbc->unit_id.bts_id == bts_id)
230 return ipbc;
231 }
232
233 return NULL;
234}
235
236struct ipa_proxy_conn *alloc_conn(void)
237{
238 struct ipa_proxy_conn *ipc;
239
240 ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
241 if (!ipc)
242 return NULL;
243
244 INIT_LLIST_HEAD(&ipc->tx_queue);
245
246 return ipc;
247}
248
249static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
250{
251 unsigned int i, len;
252
253 for (i = 0; i <= 0xff; i++) {
254 if (!TLVP_PRESENT(tlvp, i))
255 continue;
256
257 len = TLVP_LEN(tlvp, i);
258#if 0
259 if (!ipbc->id_tags[i])
260 ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
261 else
262#endif
Harald Weltea16ef3d2009-12-23 23:35:51 +0100263 ipbc->id_tags[i] = talloc_realloc_size(ipbc,
Harald Welte2ca7c312009-12-23 22:44:04 +0100264 ipbc->id_tags[i], len);
265 if (!ipbc->id_tags[i])
266 return -ENOMEM;
267
268 memset(ipbc->id_tags[i], 0, len);
269 //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
270 }
271 return 0;
272}
273
274
275static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
276
277#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
278
279static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
280 struct ipa_bts_conn *ipbc, u_int8_t trx_id)
281{
282 if (ipbc)
Harald Weltedc5062b2010-03-26 21:28:59 +0800283 logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
Harald Welte2ca7c312009-12-23 22:44:04 +0100284 ipbc->unit_id.bts_id, trx_id);
285 else
Harald Weltedc5062b2010-03-26 21:28:59 +0800286 logp2(ss, lvl, file, line, 0, "unknown ");
Harald Welte2ca7c312009-12-23 22:44:04 +0100287}
288
289/* UDP socket handling */
290
291static int make_sock(struct bsc_fd *bfd, u_int16_t port, int proto, int priv_nr,
292 int (*cb)(struct bsc_fd *fd, unsigned int what),
293 void *data)
294{
295 struct sockaddr_in addr;
296 int ret, on = 1;
297
298 bfd->fd = socket(AF_INET, SOCK_DGRAM, proto);
299 bfd->cb = cb;
300 bfd->when = BSC_FD_READ;
301 bfd->data = data;
302 bfd->priv_nr = priv_nr;
303
304 memset(&addr, 0, sizeof(addr));
305 addr.sin_family = AF_INET;
306 addr.sin_port = htons(port);
307 addr.sin_addr.s_addr = INADDR_ANY;
308
309 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
310
311 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
312 if (ret < 0) {
313 LOGP(DINP, LOGL_ERROR, "could not bind socket: %s\n",
314 strerror(errno));
315 return -EIO;
316 }
317
318 ret = bsc_register_fd(bfd);
319 if (ret < 0) {
320 perror("register UDP fd");
321 return ret;
322 }
323 return 0;
324}
325
326static int handle_udp_read(struct bsc_fd *bfd)
327{
328 struct ipa_bts_conn *ipbc = bfd->data;
329 struct ipa_proxy_conn *other_conn = NULL;
330 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
331 struct ipaccess_head *hh;
332 int ret;
333
334 /* with UDP sockets, we cannot read partial packets but have to read
335 * all of it in one go */
336 hh = (struct ipaccess_head *) msg->data;
337 ret = recv(bfd->fd, msg->data, msg->data_len, 0);
338 if (ret < 0) {
Harald Weltefb339572009-12-24 13:35:18 +0100339 if (errno != EAGAIN)
340 LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +0100341 msgb_free(msg);
342 return ret;
343 }
344 if (ret == 0) {
345 DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
346 bsc_unregister_fd(bfd);
347 close(bfd->fd);
348 bfd->fd = -1;
349 msgb_free(msg);
350 return -EIO;
351 }
352 if (ret < sizeof(*hh)) {
353 DEBUGP(DINP, "could not even read header!?!\n");
354 msgb_free(msg);
355 return -EIO;
356 }
357 msgb_put(msg, ret);
358 msg->l2h = msg->data + sizeof(*hh);
359 DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len));
360
361 if (hh->len != msg->len - sizeof(*hh)) {
362 DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
363 msg->len, msg->len - 3, hh->len);
364 msgb_free(msg);
365 return -EIO;
366 }
367
368 switch (bfd->priv_nr & 0xff) {
369 case UDP_TO_BTS:
370 /* injection towards BTS */
371 switch (hh->proto) {
372 case IPAC_PROTO_RSL:
373 /* FIXME: what to do about TRX > 0 */
374 other_conn = ipbc->rsl_conn[0];
375 break;
376 default:
377 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
378 "OML FD\n", hh->proto);
379 /* fall through */
380 case IPAC_PROTO_IPACCESS:
381 case IPAC_PROTO_OML:
382 other_conn = ipbc->oml_conn;
383 break;
384 }
385 break;
386 case UDP_TO_BSC:
387 /* injection towards BSC */
388 switch (hh->proto) {
389 case IPAC_PROTO_RSL:
390 /* FIXME: what to do about TRX > 0 */
391 other_conn = ipbc->bsc_rsl_conn[0];
392 break;
393 default:
394 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
395 "OML FD\n", hh->proto);
396 case IPAC_PROTO_IPACCESS:
397 case IPAC_PROTO_OML:
398 other_conn = ipbc->bsc_oml_conn;
399 break;
400 }
401 break;
402 default:
403 DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
404 break;
405 }
406
407 if (other_conn) {
408 /* enqueue the message for TX on the respective FD */
409 msgb_enqueue(&other_conn->tx_queue, msg);
410 other_conn->fd.when |= BSC_FD_WRITE;
411 } else
412 msgb_free(msg);
413
414 return 0;
415}
416
417static int handle_udp_write(struct bsc_fd *bfd)
418{
419 /* not implemented yet */
420 bfd->when &= ~BSC_FD_WRITE;
421
422 return -EIO;
423}
424
425/* callback from select.c in case one of the fd's can be read/written */
426static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what)
427{
428 int rc = 0;
429
430 if (what & BSC_FD_READ)
431 rc = handle_udp_read(bfd);
432 if (what & BSC_FD_WRITE)
433 rc = handle_udp_write(bfd);
434
435 return rc;
436}
437
438
439static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd,
440 u_int16_t site_id, u_int16_t bts_id,
441 u_int16_t trx_id, struct tlv_parsed *tlvp,
442 struct msgb *msg)
443{
444 struct ipa_bts_conn *ipbc;
445 u_int16_t udp_port;
446 int ret = 0;
447 struct sockaddr_in sin;
448
449 memset(&sin, 0, sizeof(sin));
450 sin.sin_family = AF_INET;
451 inet_aton(bsc_ipaddr, &sin.sin_addr);
452
453 DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
454 site_id, bts_id, trx_id);
455
456 /* OML needs to be established before RSL */
457 if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
458 DEBUGPC(DINP, "Not a OML connection ?!?\n");
459 return -EIO;
460 }
461
462 /* allocate new BTS connection data structure */
463 ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
464 if (!ipbc) {
465 ret = -ENOMEM;
466 goto err_out;
467 }
468
469 DEBUGPC(DINP, "Created BTS Conn data structure\n");
470 ipbc->ipp = ipp;
471 ipbc->unit_id.site_id = site_id;
472 ipbc->unit_id.bts_id = bts_id;
473 ipbc->oml_conn = ipc;
474 ipc->bts_conn = ipbc;
475
476 /* store the content of the ID TAGS for later reference */
477 store_idtags(ipbc, tlvp);
478 ipbc->id_resp_len = msg->len;
479 ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
480 memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
481
482 /* Create OML TCP connection towards BSC */
Harald Welte87ed5cd2009-12-23 22:47:53 +0100483 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte2ca7c312009-12-23 22:44:04 +0100484 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
485 if (!ipbc->bsc_oml_conn) {
486 ret = -EIO;
487 goto err_bsc_conn;
488 }
489
490 DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
491 site_id, bts_id, trx_id);
492
493 /* Create UDP socket for BTS packet injection */
494 udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
495 ret = make_sock(&ipbc->udp_bts_fd, udp_port, IPPROTO_UDP,
496 UDP_TO_BTS, udp_fd_cb, ipbc);
497 if (ret < 0)
498 goto err_udp_bts;
499 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
500 "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
501
502 /* Create UDP socket for BSC packet injection */
503 udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
504 ret = make_sock(&ipbc->udp_bsc_fd, udp_port, IPPROTO_UDP,
505 UDP_TO_BSC, udp_fd_cb, ipbc);
506 if (ret < 0)
507 goto err_udp_bsc;
508 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
509 "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +0800510
511
512 /* GPRS NS related code */
513 if (gprs_ns_ipaddr) {
514 struct sockaddr_in sock;
515 socklen_t len = sizeof(sock);
516 ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc);
517 if (ret < 0) {
518 LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
519 goto err_udp_bsc;
520 }
521
522 ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
523 ipbc->gprs_local_port = ntohs(sock.sin_port);
524 LOGP(DINP, LOGL_NOTICE,
525 "Created GPRS NS Socket. Listening on: %s:%d\n",
526 inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
527
528 ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
529 ipbc->bts_addr = sock.sin_addr;
530 }
531
Harald Welte2ca7c312009-12-23 22:44:04 +0100532 llist_add(&ipbc->list, &ipp->bts_list);
533
534 return 0;
535
536err_udp_bsc:
537 bsc_unregister_fd(&ipbc->udp_bts_fd);
538err_udp_bts:
539 bsc_unregister_fd(&ipbc->bsc_oml_conn->fd);
540 close(ipbc->bsc_oml_conn->fd.fd);
541 talloc_free(ipbc->bsc_oml_conn);
542 ipbc->bsc_oml_conn = NULL;
543err_bsc_conn:
544 talloc_free(ipbc->id_resp);
545 talloc_free(ipbc);
546#if 0
547 bsc_unregister_fd(bfd);
548 close(bfd->fd);
549 talloc_free(bfd);
550#endif
551err_out:
552 return ret;
553}
554
555static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
556 struct bsc_fd *bfd)
557{
558 struct tlv_parsed tlvp;
559 u_int8_t msg_type = *(msg->l2h);
560 u_int16_t site_id, bts_id, trx_id;
561 struct ipa_bts_conn *ipbc;
562 int ret = 0;
563
564 switch (msg_type) {
565 case IPAC_MSGT_PING:
566 ret = write(bfd->fd, pong, sizeof(pong));
567 if (ret < 0)
568 return ret;
569 if (ret < sizeof(pong)) {
570 DEBUGP(DINP, "short write\n");
571 return -EIO;
572 }
573 break;
574 case IPAC_MSGT_PONG:
575 DEBUGP(DMI, "PONG!\n");
576 break;
577 case IPAC_MSGT_ID_RESP:
578 DEBUGP(DMI, "ID_RESP ");
579 /* parse tags, search for Unit ID */
580 ipac_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
581 msgb_l2len(msg)-2);
582 DEBUGP(DMI, "\n");
583
584 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
585 LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
586 return -EIO;
587 }
588
589 /* lookup BTS, create sign_link, ... */
Holger Hans Peter Freyther82ae7162010-03-30 15:20:46 +0200590 site_id = bts_id = trx_id = 0;
Harald Welte2ca7c312009-12-23 22:44:04 +0100591 parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
592 &site_id, &bts_id, &trx_id);
593 ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
594 if (!ipbc) {
595 /* We have not found an ipbc (per-bts proxy instance)
596 * for this BTS yet. The first connection of a new BTS must
597 * be a OML connection. We allocate the associated data structures,
598 * and try to connect to the remote end */
599
600 return ipbc_alloc_connect(ipc, bfd, site_id, bts_id,
601 trx_id, &tlvp, msg);
602 /* if this fails, the caller will clean up bfd */
603 } else {
604 struct sockaddr_in sin;
605 memset(&sin, 0, sizeof(sin));
606 sin.sin_family = AF_INET;
607 inet_aton(bsc_ipaddr, &sin.sin_addr);
608
609 DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
610 site_id, bts_id, trx_id);
611
612 if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
613 LOGP(DINP, LOGL_ERROR, "Second OML connection from "
614 "same BTS ?!?\n");
615 return 0;
616 }
617
618 if (trx_id > MAX_TRX) {
619 LOGP(DINP, LOGL_ERROR, "We don't support more "
620 "than %u TRX\n", MAX_TRX);
621 return -EINVAL;
622 }
623
624 ipc->bts_conn = ipbc;
625 /* store TRX number in higher 8 bit of the bfd private number */
626 bfd->priv_nr |= trx_id << 8;
627 ipbc->rsl_conn[trx_id] = ipc;
628
629 /* Create RSL TCP connection towards BSC */
Harald Welte87ed5cd2009-12-23 22:47:53 +0100630 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte2ca7c312009-12-23 22:44:04 +0100631 ipbc->bsc_rsl_conn[trx_id] =
632 connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
633 if (!ipbc->bsc_oml_conn)
634 return -EIO;
635 DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
636 site_id, bts_id, trx_id);
637 }
638 break;
639 case IPAC_MSGT_ID_GET:
640 DEBUGP(DMI, "ID_GET\n");
641 if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
642 (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
643 DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
644 return -EIO;
645 }
646 ipbc = ipc->bts_conn;
647 if (!ipbc) {
648 DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
649 return -EIO;
650 }
651 ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
652 break;
653 case IPAC_MSGT_ID_ACK:
654 DEBUGP(DMI, "ID_ACK? -> ACK!\n");
655 ret = write(bfd->fd, id_ack, sizeof(id_ack));
656 break;
657 }
658 return 0;
659}
660
661struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
662{
663 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
664 struct ipaccess_head *hh;
665 int len, ret = 0;
666
667 if (!msg) {
668 *error = -ENOMEM;
669 return NULL;
670 }
671
672 /* first read our 3-byte header */
673 hh = (struct ipaccess_head *) msg->data;
674 ret = recv(bfd->fd, msg->data, 3, 0);
675 if (ret < 0) {
Harald Weltefb339572009-12-24 13:35:18 +0100676 if (errno != EAGAIN)
Harald Welteda956932009-12-24 12:49:43 +0100677 LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +0100678 msgb_free(msg);
679 *error = ret;
680 return NULL;
681 } else if (ret == 0) {
682 msgb_free(msg);
683 *error = ret;
684 return NULL;
685 }
686
687 msgb_put(msg, ret);
688
689 /* then read te length as specified in header */
690 msg->l2h = msg->data + sizeof(*hh);
691 len = ntohs(hh->len);
692 ret = recv(bfd->fd, msg->l2h, len, 0);
693 if (ret < len) {
694 LOGP(DINP, LOGL_ERROR, "short read!\n");
695 msgb_free(msg);
696 *error = -EIO;
697 return NULL;
698 }
699 msgb_put(msg, ret);
700
701 return msg;
702}
703
704static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
705 unsigned int priv_nr)
706{
707 struct ipa_proxy_conn *bsc_conn;
708 unsigned int trx_id = priv_nr >> 8;
709
710 switch (priv_nr & 0xff) {
711 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
712 bsc_conn = ipbc->bsc_oml_conn;
713 break;
714 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
715 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
716 break;
717 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
718 bsc_conn = ipbc->oml_conn;
719 break;
720 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
721 bsc_conn = ipbc->rsl_conn[trx_id];
722 break;
723 default:
724 bsc_conn = NULL;
725 break;
726 }
727 return bsc_conn;
728}
729
730static void reconn_tmr_cb(void *data)
731{
732 struct ipa_proxy *ipp = data;
733 struct ipa_bts_conn *ipbc;
734 struct sockaddr_in sin;
735 int i;
736
737 DEBUGP(DINP, "Running reconnect timer\n");
738
739 memset(&sin, 0, sizeof(sin));
740 sin.sin_family = AF_INET;
741 inet_aton(bsc_ipaddr, &sin.sin_addr);
742
743 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
744 /* if OML to BSC is dead, try to restore it */
745 if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
Harald Welte87ed5cd2009-12-23 22:47:53 +0100746 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte2ca7c312009-12-23 22:44:04 +0100747 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
748 LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
749 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
750 if (!ipbc->bsc_oml_conn)
751 goto reschedule;
752 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
753 LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
754 }
755 /* if we (still) don't have a OML connection, skip RSL */
756 if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
757 continue;
758
759 for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
760 unsigned int priv_nr;
761 /* don't establish RSL links which we don't have */
762 if (!ipbc->rsl_conn[i])
763 continue;
764 if (ipbc->bsc_rsl_conn[i])
765 continue;
766 priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
767 priv_nr &= ~0xff;
768 priv_nr |= RSL_TO_BSC;
Harald Welte87ed5cd2009-12-23 22:47:53 +0100769 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte2ca7c312009-12-23 22:44:04 +0100770 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
771 LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
772 ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
773 if (!ipbc->bsc_rsl_conn)
774 goto reschedule;
775 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
776 LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
777 }
778 }
779 return;
780
781reschedule:
782 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
783}
784
785static void handle_dead_socket(struct bsc_fd *bfd)
786{
787 struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
788 struct ipa_proxy_conn *bsc_conn; /* remote conn */
789 struct ipa_bts_conn *ipbc = ipc->bts_conn;
790 unsigned int trx_id = bfd->priv_nr >> 8;
791 struct msgb *msg, *msg2;
792
793 bsc_unregister_fd(bfd);
794 close(bfd->fd);
795 bfd->fd = -1;
796
797 /* FIXME: clear tx_queue, remove all references, etc. */
798 llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
799 msgb_free(msg);
800
801 switch (bfd->priv_nr & 0xff) {
802 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
803 ipbc->oml_conn = NULL;
804 bsc_conn = ipbc->bsc_oml_conn;
805 /* close the connection to the BSC */
806 bsc_unregister_fd(&bsc_conn->fd);
807 close(bsc_conn->fd.fd);
808 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
809 msgb_free(msg);
810 talloc_free(bsc_conn);
811 ipbc->bsc_oml_conn = NULL;
812 /* FIXME: do we need to delete the entire ipbc ? */
813 break;
814 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
815 ipbc->rsl_conn[trx_id] = NULL;
816 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
817 /* close the connection to the BSC */
818 bsc_unregister_fd(&bsc_conn->fd);
819 close(bsc_conn->fd.fd);
820 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
821 msgb_free(msg);
822 talloc_free(bsc_conn);
823 ipbc->bsc_rsl_conn[trx_id] = NULL;
824 break;
825 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
826 ipbc->bsc_oml_conn = NULL;
827 bsc_conn = ipbc->oml_conn;
828 /* start reconnect timer */
829 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
830 break;
831 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
832 ipbc->bsc_rsl_conn[trx_id] = NULL;
833 bsc_conn = ipbc->rsl_conn[trx_id];
834 /* start reconnect timer */
835 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
836 break;
837 default:
838 bsc_conn = NULL;
839 break;
840 }
841
842 talloc_free(ipc);
843}
844
845static int handle_tcp_read(struct bsc_fd *bfd)
846{
847 struct ipa_proxy_conn *ipc = bfd->data;
848 struct ipa_bts_conn *ipbc = ipc->bts_conn;
849 struct ipa_proxy_conn *bsc_conn;
Harald Weltea16ef3d2009-12-23 23:35:51 +0100850 struct msgb *msg;
Harald Welte2ca7c312009-12-23 22:44:04 +0100851 struct ipaccess_head *hh;
852 int ret = 0;
853 char *btsbsc;
854
Harald Welte2ca7c312009-12-23 22:44:04 +0100855 if ((bfd->priv_nr & 0xff) <= 2)
856 btsbsc = "BTS";
857 else
858 btsbsc = "BSC";
859
860 msg = ipaccess_read_msg(bfd, &ret);
861 if (!msg) {
862 if (ret == 0) {
863 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
864 LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
865 "dead socket\n", btsbsc);
866 handle_dead_socket(bfd);
867 }
868 return ret;
869 }
870
871 msgb_put(msg, ret);
872 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
873 DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
874
875 hh = (struct ipaccess_head *) msg->data;
876 if (hh->proto == IPAC_PROTO_IPACCESS) {
877 ret = ipaccess_rcvmsg(ipc, msg, bfd);
878 if (ret < 0) {
879 bsc_unregister_fd(bfd);
880 close(bfd->fd);
881 bfd->fd = -1;
882 talloc_free(bfd);
883 }
884 /* we do not forward the CCM protocol through the
885 * proxy but rather terminate it ourselves */
886 msgb_free(msg);
887 return ret;
888 }
889
890 if (!ipbc) {
891 LOGP(DINP, LOGL_ERROR,
892 "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
893 msgb_free(msg);
894 return -EIO;
895 }
896
897 bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
898 if (bsc_conn) {
899 /* enqueue packet towards BSC */
900 msgb_enqueue(&bsc_conn->tx_queue, msg);
901 /* mark respective filedescriptor as 'we want to write' */
902 bsc_conn->fd.when |= BSC_FD_WRITE;
903 } else {
904 logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
905 LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
906 "since remote connection is dead\n", btsbsc);
907 msgb_free(msg);
908 }
909
910 return ret;
911}
912
913/* a TCP socket is ready to be written to */
914static int handle_tcp_write(struct bsc_fd *bfd)
915{
916 struct ipa_proxy_conn *ipc = bfd->data;
917 struct ipa_bts_conn *ipbc = ipc->bts_conn;
918 struct llist_head *lh;
919 struct msgb *msg;
920 char *btsbsc;
921 int ret;
922
923 if ((bfd->priv_nr & 0xff) <= 2)
924 btsbsc = "BTS";
925 else
926 btsbsc = "BSC";
927
928
929 /* get the next msg for this timeslot */
930 if (llist_empty(&ipc->tx_queue)) {
931 bfd->when &= ~BSC_FD_WRITE;
932 return 0;
933 }
934 lh = ipc->tx_queue.next;
935 llist_del(lh);
936 msg = llist_entry(lh, struct msgb, list);
937
938 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
939 DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
940 hexdump(msg->data, msg->len));
941
942 ret = send(bfd->fd, msg->data, msg->len, 0);
943 msgb_free(msg);
944
945 if (ret == 0) {
946 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
947 LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
948 handle_dead_socket(bfd);
949 }
950
951 return ret;
952}
953
954/* callback from select.c in case one of the fd's can be read/written */
955static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
956{
957 int rc = 0;
958
959 if (what & BSC_FD_READ) {
960 rc = handle_tcp_read(bfd);
961 if (rc < 0)
962 return rc;
963 }
964 if (what & BSC_FD_WRITE)
965 rc = handle_tcp_write(bfd);
966
967 return rc;
968}
969
970/* callback of the listening filedescriptor */
971static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
972{
973 int ret;
974 struct ipa_proxy_conn *ipc;
975 struct bsc_fd *bfd;
976 struct sockaddr_in sa;
977 socklen_t sa_len = sizeof(sa);
978
979 if (!(what & BSC_FD_READ))
980 return 0;
981
982 ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
983 if (ret < 0) {
984 perror("accept");
985 return ret;
986 }
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200987 DEBUGP(DINP, "accept()ed new %s link from %s\n",
Harald Welte2ca7c312009-12-23 22:44:04 +0100988 (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
989 inet_ntoa(sa.sin_addr));
990
991 ipc = alloc_conn();
992 if (!ipc) {
993 close(ret);
994 return -ENOMEM;
995 }
996
997 bfd = &ipc->fd;
998 bfd->fd = ret;
999 bfd->data = ipc;
1000 bfd->priv_nr = listen_bfd->priv_nr;
1001 bfd->cb = ipaccess_fd_cb;
1002 bfd->when = BSC_FD_READ;
1003 ret = bsc_register_fd(bfd);
1004 if (ret < 0) {
1005 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
1006 close(bfd->fd);
1007 talloc_free(ipc);
1008 return ret;
1009 }
1010
1011 /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
1012 ret = write(bfd->fd, id_req, sizeof(id_req));
1013
1014 return 0;
1015}
1016
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001017static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
1018{
1019 int ret;
1020 struct sockaddr_in addr;
1021 socklen_t len = sizeof(addr);
1022 memset(&addr, 0, sizeof(addr));
1023
1024 addr.sin_family = AF_INET;
1025 addr.sin_port = port;
1026 addr.sin_addr = ip;
1027
1028 ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
1029 if (ret < 0) {
1030 LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
1031 }
1032}
1033
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001034static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
1035{
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001036 struct ipa_bts_conn *bts;
1037 char buf[4096];
1038 int ret;
1039 struct sockaddr_in sock;
1040 socklen_t len = sizeof(sock);
1041
1042 /* 1. get the data... */
1043 ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
1044 if (ret < 0) {
1045 LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
1046 return -1;
1047 }
1048
1049 bts = bfd->data;
1050
1051 /* 2. figure out where to send it to */
1052 if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
1053 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
1054 send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
1055 } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
1056 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
1057 send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
1058 }
1059
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001060 return 0;
1061}
1062
Harald Welte2ca7c312009-12-23 22:44:04 +01001063static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr,
1064 int (*cb)(struct bsc_fd *fd, unsigned int what))
1065{
1066 struct sockaddr_in addr;
1067 int ret, on = 1;
1068
1069 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1070 bfd->cb = cb;
1071 bfd->when = BSC_FD_READ;
1072 bfd->priv_nr = priv_nr;
1073
1074 memset(&addr, 0, sizeof(addr));
1075 addr.sin_family = AF_INET;
1076 addr.sin_port = htons(port);
1077 if (!listen_ipaddr)
1078 addr.sin_addr.s_addr = INADDR_ANY;
1079 else
1080 inet_aton(listen_ipaddr, &addr.sin_addr);
1081
1082 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1083
1084 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1085 if (ret < 0) {
Holger Hans Peter Freyther76706512010-06-09 15:17:53 +08001086 LOGP(DINP, LOGL_ERROR,
1087 "Could not bind listen socket for IP %s with error: %s.\n",
1088 listen_ipaddr, strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +01001089 return -EIO;
1090 }
1091
1092 ret = listen(bfd->fd, 1);
1093 if (ret < 0) {
1094 perror("listen");
1095 return ret;
1096 }
1097
1098 ret = bsc_register_fd(bfd);
1099 if (ret < 0) {
1100 perror("register_listen_fd");
1101 return ret;
1102 }
1103 return 0;
1104}
1105
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001106static 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 +08001107{
1108 struct sockaddr_in addr;
1109 int ret;
1110
1111 bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1112 bfd->cb = cb;
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001113 bfd->data = data;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001114 bfd->when = BSC_FD_READ;
1115
1116 memset(&addr, 0, sizeof(addr));
1117 addr.sin_family = AF_INET;
1118 addr.sin_port = 0;
1119 inet_aton(listen_ipaddr, &addr.sin_addr);
1120
1121 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1122 if (ret < 0) {
1123 LOGP(DINP, LOGL_ERROR,
1124 "Could not bind n socket for IP %s with error: %s.\n",
1125 listen_ipaddr, strerror(errno));
1126 return -EIO;
1127 }
1128
1129 ret = bsc_register_fd(bfd);
1130 if (ret < 0) {
1131 perror("register_listen_fd");
1132 return ret;
1133 }
1134 return 0;
1135}
1136
Harald Welte2ca7c312009-12-23 22:44:04 +01001137/* Actively connect to a BSC. */
1138static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
1139{
1140 struct ipa_proxy_conn *ipc;
1141 struct bsc_fd *bfd;
1142 int ret, on = 1;
1143
1144 ipc = alloc_conn();
1145 if (!ipc)
1146 return NULL;
1147
1148 ipc->bts_conn = data;
1149
1150 bfd = &ipc->fd;
1151 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1152 bfd->cb = ipaccess_fd_cb;
1153 bfd->when = BSC_FD_READ | BSC_FD_WRITE;
1154 bfd->data = ipc;
1155 bfd->priv_nr = priv_nr;
1156
1157 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1158
1159 ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
1160 if (ret < 0) {
Holger Hans Peter Freyther6cb9b232010-06-09 15:15:11 +08001161 LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
1162 inet_ntoa(sa->sin_addr));
Harald Welte2ca7c312009-12-23 22:44:04 +01001163 close(bfd->fd);
1164 talloc_free(ipc);
1165 return NULL;
1166 }
1167
1168 /* pre-fill tx_queue with identity request */
1169 ret = bsc_register_fd(bfd);
1170 if (ret < 0) {
1171 close(bfd->fd);
1172 talloc_free(ipc);
1173 return NULL;
1174 }
1175
1176 return ipc;
1177}
1178
1179static int ipaccess_proxy_setup(void)
1180{
1181 int ret;
1182
1183 ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
1184 if (!ipp)
1185 return -ENOMEM;
1186 INIT_LLIST_HEAD(&ipp->bts_list);
1187 ipp->reconn_timer.cb = reconn_tmr_cb;
1188 ipp->reconn_timer.data = ipp;
1189
1190 /* Listen for OML connections */
Harald Welte87ed5cd2009-12-23 22:47:53 +01001191 ret = make_listen_sock(&ipp->oml_listen_fd, IPA_TCP_PORT_OML,
1192 OML_FROM_BTS, listen_fd_cb);
Harald Welte2ca7c312009-12-23 22:44:04 +01001193 if (ret < 0)
1194 return ret;
1195
1196 /* Listen for RSL connections */
Harald Welte87ed5cd2009-12-23 22:47:53 +01001197 ret = make_listen_sock(&ipp->rsl_listen_fd, IPA_TCP_PORT_RSL,
1198 RSL_FROM_BTS, listen_fd_cb);
Harald Welte2ca7c312009-12-23 22:44:04 +01001199
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001200 if (ret < 0)
1201 return ret;
1202
1203 /* Connect the GPRS NS Socket */
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001204 if (gprs_ns_ipaddr)
1205 inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001206
Harald Welte2ca7c312009-12-23 22:44:04 +01001207 return ret;
1208}
1209
1210static void signal_handler(int signal)
1211{
1212 fprintf(stdout, "signal %u received\n", signal);
1213
1214 switch (signal) {
1215 case SIGABRT:
1216 /* in case of abort, we want to obtain a talloc report
1217 * and then return to the caller, who will abort the process */
1218 case SIGUSR1:
1219 talloc_report_full(tall_bsc_ctx, stderr);
1220 break;
1221 default:
1222 break;
1223 }
1224}
1225
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001226static void print_help()
1227{
1228 printf(" ipaccess-proxy is a proxy BTS.\n");
1229 printf(" -h --help. This help text.\n");
1230 printf(" -l --listen IP. The ip to listen to.\n");
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001231 printf(" -b --bsc IP. The BSC IP address.\n");
1232 printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
1233 printf("\n");
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001234 printf(" -s --disable-color. Disable the color inside the logging message.\n");
1235 printf(" -e --log-level number. Set the global loglevel.\n");
1236 printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
1237 printf(" -V --version. Print the version of OpenBSC.\n");
1238}
1239
1240static void print_usage()
1241{
1242 printf("Usage: ipaccess-proxy\n");
1243}
1244
1245static void handle_options(int argc, char** argv)
1246{
1247 while (1) {
1248 int option_index = 0, c;
1249 static struct option long_options[] = {
1250 {"help", 0, 0, 'h'},
1251 {"disable-color", 0, 0, 's'},
1252 {"timestamp", 0, 0, 'T'},
1253 {"log-level", 1, 0, 'e'},
1254 {"listen", 1, 0, 'l'},
1255 {"bsc", 1, 0, 'b'},
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001256 {"udp", 1, 0, 'u'},
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001257 {0, 0, 0, 0}
1258 };
1259
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001260 c = getopt_long(argc, argv, "hsTe:l:b:g:",
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001261 long_options, &option_index);
1262 if (c == -1)
1263 break;
1264
1265 switch (c) {
1266 case 'h':
1267 print_usage();
1268 print_help();
1269 exit(0);
1270 case 'l':
1271 listen_ipaddr = optarg;
1272 break;
1273 case 'b':
1274 bsc_ipaddr = optarg;
1275 break;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001276 case 'g':
1277 gprs_ns_ipaddr = optarg;
1278 break;
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001279 case 's':
1280 log_set_use_color(stderr_target, 0);
1281 break;
1282 case 'T':
1283 log_set_print_timestamp(stderr_target, 1);
1284 break;
1285 case 'e':
1286 log_set_log_level(stderr_target, atoi(optarg));
1287 break;
1288 default:
1289 /* ignore */
1290 break;
1291 }
1292 }
1293}
1294
Harald Welte2ca7c312009-12-23 22:44:04 +01001295int main(int argc, char **argv)
1296{
1297 int rc;
1298
1299 listen_ipaddr = "192.168.100.11";
1300 bsc_ipaddr = "192.168.100.239";
1301
1302 tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
1303
Harald Weltedc5062b2010-03-26 21:28:59 +08001304 log_init(&log_info);
1305 stderr_target = log_target_create_stderr();
1306 log_add_target(stderr_target);
1307 log_set_all_filter(stderr_target, 1);
1308 log_parse_category_mask(stderr_target, "DINP:DMI");
Harald Welte2ca7c312009-12-23 22:44:04 +01001309
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001310 handle_options(argc, argv);
1311
Harald Welte2ca7c312009-12-23 22:44:04 +01001312 rc = ipaccess_proxy_setup();
1313 if (rc < 0)
1314 exit(1);
1315
1316 signal(SIGUSR1, &signal_handler);
1317 signal(SIGABRT, &signal_handler);
1318
1319 while (1) {
1320 bsc_select_main(0);
1321 }
1322}