blob: 59895c47c1dd6b538dc546b78027e1a6cb5ea695 [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;
Holger Hans Peter Freyther0897dad2010-06-09 17:38:59 +0800657 default:
658 LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
659 return 1;
660 break;
Harald Welte2ca7c312009-12-23 22:44:04 +0100661 }
662 return 0;
663}
664
665struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
666{
667 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
668 struct ipaccess_head *hh;
669 int len, ret = 0;
670
671 if (!msg) {
672 *error = -ENOMEM;
673 return NULL;
674 }
675
676 /* first read our 3-byte header */
677 hh = (struct ipaccess_head *) msg->data;
678 ret = recv(bfd->fd, msg->data, 3, 0);
679 if (ret < 0) {
Harald Weltefb339572009-12-24 13:35:18 +0100680 if (errno != EAGAIN)
Harald Welteda956932009-12-24 12:49:43 +0100681 LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +0100682 msgb_free(msg);
683 *error = ret;
684 return NULL;
685 } else if (ret == 0) {
686 msgb_free(msg);
687 *error = ret;
688 return NULL;
689 }
690
691 msgb_put(msg, ret);
692
693 /* then read te length as specified in header */
694 msg->l2h = msg->data + sizeof(*hh);
695 len = ntohs(hh->len);
696 ret = recv(bfd->fd, msg->l2h, len, 0);
697 if (ret < len) {
698 LOGP(DINP, LOGL_ERROR, "short read!\n");
699 msgb_free(msg);
700 *error = -EIO;
701 return NULL;
702 }
703 msgb_put(msg, ret);
704
705 return msg;
706}
707
708static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
709 unsigned int priv_nr)
710{
711 struct ipa_proxy_conn *bsc_conn;
712 unsigned int trx_id = priv_nr >> 8;
713
714 switch (priv_nr & 0xff) {
715 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
716 bsc_conn = ipbc->bsc_oml_conn;
717 break;
718 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
719 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
720 break;
721 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
722 bsc_conn = ipbc->oml_conn;
723 break;
724 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
725 bsc_conn = ipbc->rsl_conn[trx_id];
726 break;
727 default:
728 bsc_conn = NULL;
729 break;
730 }
731 return bsc_conn;
732}
733
734static void reconn_tmr_cb(void *data)
735{
736 struct ipa_proxy *ipp = data;
737 struct ipa_bts_conn *ipbc;
738 struct sockaddr_in sin;
739 int i;
740
741 DEBUGP(DINP, "Running reconnect timer\n");
742
743 memset(&sin, 0, sizeof(sin));
744 sin.sin_family = AF_INET;
745 inet_aton(bsc_ipaddr, &sin.sin_addr);
746
747 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
748 /* if OML to BSC is dead, try to restore it */
749 if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
Harald Welte87ed5cd2009-12-23 22:47:53 +0100750 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte2ca7c312009-12-23 22:44:04 +0100751 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
752 LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
753 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
754 if (!ipbc->bsc_oml_conn)
755 goto reschedule;
756 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
757 LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
758 }
759 /* if we (still) don't have a OML connection, skip RSL */
760 if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
761 continue;
762
763 for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
764 unsigned int priv_nr;
765 /* don't establish RSL links which we don't have */
766 if (!ipbc->rsl_conn[i])
767 continue;
768 if (ipbc->bsc_rsl_conn[i])
769 continue;
770 priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
771 priv_nr &= ~0xff;
772 priv_nr |= RSL_TO_BSC;
Harald Welte87ed5cd2009-12-23 22:47:53 +0100773 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte2ca7c312009-12-23 22:44:04 +0100774 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
775 LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
776 ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
777 if (!ipbc->bsc_rsl_conn)
778 goto reschedule;
779 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
780 LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
781 }
782 }
783 return;
784
785reschedule:
786 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
787}
788
789static void handle_dead_socket(struct bsc_fd *bfd)
790{
791 struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
792 struct ipa_proxy_conn *bsc_conn; /* remote conn */
793 struct ipa_bts_conn *ipbc = ipc->bts_conn;
794 unsigned int trx_id = bfd->priv_nr >> 8;
795 struct msgb *msg, *msg2;
796
797 bsc_unregister_fd(bfd);
798 close(bfd->fd);
799 bfd->fd = -1;
800
801 /* FIXME: clear tx_queue, remove all references, etc. */
802 llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
803 msgb_free(msg);
804
805 switch (bfd->priv_nr & 0xff) {
806 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
807 ipbc->oml_conn = NULL;
808 bsc_conn = ipbc->bsc_oml_conn;
809 /* close the connection to the BSC */
810 bsc_unregister_fd(&bsc_conn->fd);
811 close(bsc_conn->fd.fd);
812 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
813 msgb_free(msg);
814 talloc_free(bsc_conn);
815 ipbc->bsc_oml_conn = NULL;
816 /* FIXME: do we need to delete the entire ipbc ? */
817 break;
818 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
819 ipbc->rsl_conn[trx_id] = NULL;
820 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
821 /* close the connection to the BSC */
822 bsc_unregister_fd(&bsc_conn->fd);
823 close(bsc_conn->fd.fd);
824 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
825 msgb_free(msg);
826 talloc_free(bsc_conn);
827 ipbc->bsc_rsl_conn[trx_id] = NULL;
828 break;
829 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
830 ipbc->bsc_oml_conn = NULL;
831 bsc_conn = ipbc->oml_conn;
832 /* start reconnect timer */
833 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
834 break;
835 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
836 ipbc->bsc_rsl_conn[trx_id] = NULL;
837 bsc_conn = ipbc->rsl_conn[trx_id];
838 /* start reconnect timer */
839 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
840 break;
841 default:
842 bsc_conn = NULL;
843 break;
844 }
845
846 talloc_free(ipc);
847}
848
849static int handle_tcp_read(struct bsc_fd *bfd)
850{
851 struct ipa_proxy_conn *ipc = bfd->data;
852 struct ipa_bts_conn *ipbc = ipc->bts_conn;
853 struct ipa_proxy_conn *bsc_conn;
Harald Weltea16ef3d2009-12-23 23:35:51 +0100854 struct msgb *msg;
Harald Welte2ca7c312009-12-23 22:44:04 +0100855 struct ipaccess_head *hh;
856 int ret = 0;
857 char *btsbsc;
858
Harald Welte2ca7c312009-12-23 22:44:04 +0100859 if ((bfd->priv_nr & 0xff) <= 2)
860 btsbsc = "BTS";
861 else
862 btsbsc = "BSC";
863
864 msg = ipaccess_read_msg(bfd, &ret);
865 if (!msg) {
866 if (ret == 0) {
867 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
868 LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
869 "dead socket\n", btsbsc);
870 handle_dead_socket(bfd);
871 }
872 return ret;
873 }
874
875 msgb_put(msg, ret);
876 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
877 DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
878
879 hh = (struct ipaccess_head *) msg->data;
880 if (hh->proto == IPAC_PROTO_IPACCESS) {
881 ret = ipaccess_rcvmsg(ipc, msg, bfd);
882 if (ret < 0) {
883 bsc_unregister_fd(bfd);
884 close(bfd->fd);
885 bfd->fd = -1;
886 talloc_free(bfd);
Holger Hans Peter Freyther0897dad2010-06-09 17:38:59 +0800887 msgb_free(msg);
888 return ret;
889 } else if (ret == 0) {
890 /* we do not forward parts of the CCM protocol
891 * through the proxy but rather terminate it ourselves. */
892 msgb_free(msg);
893 return ret;
Harald Welte2ca7c312009-12-23 22:44:04 +0100894 }
Harald Welte2ca7c312009-12-23 22:44:04 +0100895 }
896
897 if (!ipbc) {
898 LOGP(DINP, LOGL_ERROR,
899 "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
900 msgb_free(msg);
901 return -EIO;
902 }
903
904 bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
905 if (bsc_conn) {
906 /* enqueue packet towards BSC */
907 msgb_enqueue(&bsc_conn->tx_queue, msg);
908 /* mark respective filedescriptor as 'we want to write' */
909 bsc_conn->fd.when |= BSC_FD_WRITE;
910 } else {
911 logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
912 LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
913 "since remote connection is dead\n", btsbsc);
914 msgb_free(msg);
915 }
916
917 return ret;
918}
919
920/* a TCP socket is ready to be written to */
921static int handle_tcp_write(struct bsc_fd *bfd)
922{
923 struct ipa_proxy_conn *ipc = bfd->data;
924 struct ipa_bts_conn *ipbc = ipc->bts_conn;
925 struct llist_head *lh;
926 struct msgb *msg;
927 char *btsbsc;
928 int ret;
929
930 if ((bfd->priv_nr & 0xff) <= 2)
931 btsbsc = "BTS";
932 else
933 btsbsc = "BSC";
934
935
936 /* get the next msg for this timeslot */
937 if (llist_empty(&ipc->tx_queue)) {
938 bfd->when &= ~BSC_FD_WRITE;
939 return 0;
940 }
941 lh = ipc->tx_queue.next;
942 llist_del(lh);
943 msg = llist_entry(lh, struct msgb, list);
944
945 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
946 DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
947 hexdump(msg->data, msg->len));
948
949 ret = send(bfd->fd, msg->data, msg->len, 0);
950 msgb_free(msg);
951
952 if (ret == 0) {
953 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
954 LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
955 handle_dead_socket(bfd);
956 }
957
958 return ret;
959}
960
961/* callback from select.c in case one of the fd's can be read/written */
962static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
963{
964 int rc = 0;
965
966 if (what & BSC_FD_READ) {
967 rc = handle_tcp_read(bfd);
968 if (rc < 0)
969 return rc;
970 }
971 if (what & BSC_FD_WRITE)
972 rc = handle_tcp_write(bfd);
973
974 return rc;
975}
976
977/* callback of the listening filedescriptor */
978static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
979{
980 int ret;
981 struct ipa_proxy_conn *ipc;
982 struct bsc_fd *bfd;
983 struct sockaddr_in sa;
984 socklen_t sa_len = sizeof(sa);
985
986 if (!(what & BSC_FD_READ))
987 return 0;
988
989 ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
990 if (ret < 0) {
991 perror("accept");
992 return ret;
993 }
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200994 DEBUGP(DINP, "accept()ed new %s link from %s\n",
Harald Welte2ca7c312009-12-23 22:44:04 +0100995 (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
996 inet_ntoa(sa.sin_addr));
997
998 ipc = alloc_conn();
999 if (!ipc) {
1000 close(ret);
1001 return -ENOMEM;
1002 }
1003
1004 bfd = &ipc->fd;
1005 bfd->fd = ret;
1006 bfd->data = ipc;
1007 bfd->priv_nr = listen_bfd->priv_nr;
1008 bfd->cb = ipaccess_fd_cb;
1009 bfd->when = BSC_FD_READ;
1010 ret = bsc_register_fd(bfd);
1011 if (ret < 0) {
1012 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
1013 close(bfd->fd);
1014 talloc_free(ipc);
1015 return ret;
1016 }
1017
1018 /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
1019 ret = write(bfd->fd, id_req, sizeof(id_req));
1020
1021 return 0;
1022}
1023
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001024static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
1025{
1026 int ret;
1027 struct sockaddr_in addr;
1028 socklen_t len = sizeof(addr);
1029 memset(&addr, 0, sizeof(addr));
1030
1031 addr.sin_family = AF_INET;
1032 addr.sin_port = port;
1033 addr.sin_addr = ip;
1034
1035 ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
1036 if (ret < 0) {
1037 LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
1038 }
1039}
1040
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001041static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
1042{
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001043 struct ipa_bts_conn *bts;
1044 char buf[4096];
1045 int ret;
1046 struct sockaddr_in sock;
1047 socklen_t len = sizeof(sock);
1048
1049 /* 1. get the data... */
1050 ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
1051 if (ret < 0) {
1052 LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
1053 return -1;
1054 }
1055
1056 bts = bfd->data;
1057
1058 /* 2. figure out where to send it to */
1059 if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
1060 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
1061 send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
1062 } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
1063 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
1064 send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
1065 }
1066
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001067 return 0;
1068}
1069
Harald Welte2ca7c312009-12-23 22:44:04 +01001070static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr,
1071 int (*cb)(struct bsc_fd *fd, unsigned int what))
1072{
1073 struct sockaddr_in addr;
1074 int ret, on = 1;
1075
1076 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1077 bfd->cb = cb;
1078 bfd->when = BSC_FD_READ;
1079 bfd->priv_nr = priv_nr;
1080
1081 memset(&addr, 0, sizeof(addr));
1082 addr.sin_family = AF_INET;
1083 addr.sin_port = htons(port);
1084 if (!listen_ipaddr)
1085 addr.sin_addr.s_addr = INADDR_ANY;
1086 else
1087 inet_aton(listen_ipaddr, &addr.sin_addr);
1088
1089 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1090
1091 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1092 if (ret < 0) {
Holger Hans Peter Freyther76706512010-06-09 15:17:53 +08001093 LOGP(DINP, LOGL_ERROR,
1094 "Could not bind listen socket for IP %s with error: %s.\n",
1095 listen_ipaddr, strerror(errno));
Harald Welte2ca7c312009-12-23 22:44:04 +01001096 return -EIO;
1097 }
1098
1099 ret = listen(bfd->fd, 1);
1100 if (ret < 0) {
1101 perror("listen");
1102 return ret;
1103 }
1104
1105 ret = bsc_register_fd(bfd);
1106 if (ret < 0) {
1107 perror("register_listen_fd");
1108 return ret;
1109 }
1110 return 0;
1111}
1112
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001113static 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 +08001114{
1115 struct sockaddr_in addr;
1116 int ret;
1117
1118 bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1119 bfd->cb = cb;
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001120 bfd->data = data;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001121 bfd->when = BSC_FD_READ;
1122
1123 memset(&addr, 0, sizeof(addr));
1124 addr.sin_family = AF_INET;
1125 addr.sin_port = 0;
1126 inet_aton(listen_ipaddr, &addr.sin_addr);
1127
1128 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1129 if (ret < 0) {
1130 LOGP(DINP, LOGL_ERROR,
1131 "Could not bind n socket for IP %s with error: %s.\n",
1132 listen_ipaddr, strerror(errno));
1133 return -EIO;
1134 }
1135
1136 ret = bsc_register_fd(bfd);
1137 if (ret < 0) {
1138 perror("register_listen_fd");
1139 return ret;
1140 }
1141 return 0;
1142}
1143
Harald Welte2ca7c312009-12-23 22:44:04 +01001144/* Actively connect to a BSC. */
1145static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
1146{
1147 struct ipa_proxy_conn *ipc;
1148 struct bsc_fd *bfd;
1149 int ret, on = 1;
1150
1151 ipc = alloc_conn();
1152 if (!ipc)
1153 return NULL;
1154
1155 ipc->bts_conn = data;
1156
1157 bfd = &ipc->fd;
1158 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1159 bfd->cb = ipaccess_fd_cb;
1160 bfd->when = BSC_FD_READ | BSC_FD_WRITE;
1161 bfd->data = ipc;
1162 bfd->priv_nr = priv_nr;
1163
1164 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1165
1166 ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
1167 if (ret < 0) {
Holger Hans Peter Freyther6cb9b232010-06-09 15:15:11 +08001168 LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
1169 inet_ntoa(sa->sin_addr));
Harald Welte2ca7c312009-12-23 22:44:04 +01001170 close(bfd->fd);
1171 talloc_free(ipc);
1172 return NULL;
1173 }
1174
1175 /* pre-fill tx_queue with identity request */
1176 ret = bsc_register_fd(bfd);
1177 if (ret < 0) {
1178 close(bfd->fd);
1179 talloc_free(ipc);
1180 return NULL;
1181 }
1182
1183 return ipc;
1184}
1185
1186static int ipaccess_proxy_setup(void)
1187{
1188 int ret;
1189
1190 ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
1191 if (!ipp)
1192 return -ENOMEM;
1193 INIT_LLIST_HEAD(&ipp->bts_list);
1194 ipp->reconn_timer.cb = reconn_tmr_cb;
1195 ipp->reconn_timer.data = ipp;
1196
1197 /* Listen for OML connections */
Harald Welte87ed5cd2009-12-23 22:47:53 +01001198 ret = make_listen_sock(&ipp->oml_listen_fd, IPA_TCP_PORT_OML,
1199 OML_FROM_BTS, listen_fd_cb);
Harald Welte2ca7c312009-12-23 22:44:04 +01001200 if (ret < 0)
1201 return ret;
1202
1203 /* Listen for RSL connections */
Harald Welte87ed5cd2009-12-23 22:47:53 +01001204 ret = make_listen_sock(&ipp->rsl_listen_fd, IPA_TCP_PORT_RSL,
1205 RSL_FROM_BTS, listen_fd_cb);
Harald Welte2ca7c312009-12-23 22:44:04 +01001206
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001207 if (ret < 0)
1208 return ret;
1209
1210 /* Connect the GPRS NS Socket */
Holger Hans Peter Freyther952aba72010-06-09 17:07:43 +08001211 if (gprs_ns_ipaddr)
1212 inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001213
Harald Welte2ca7c312009-12-23 22:44:04 +01001214 return ret;
1215}
1216
1217static void signal_handler(int signal)
1218{
1219 fprintf(stdout, "signal %u received\n", signal);
1220
1221 switch (signal) {
1222 case SIGABRT:
1223 /* in case of abort, we want to obtain a talloc report
1224 * and then return to the caller, who will abort the process */
1225 case SIGUSR1:
1226 talloc_report_full(tall_bsc_ctx, stderr);
1227 break;
1228 default:
1229 break;
1230 }
1231}
1232
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001233static void print_help()
1234{
1235 printf(" ipaccess-proxy is a proxy BTS.\n");
1236 printf(" -h --help. This help text.\n");
1237 printf(" -l --listen IP. The ip to listen to.\n");
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001238 printf(" -b --bsc IP. The BSC IP address.\n");
1239 printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
1240 printf("\n");
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001241 printf(" -s --disable-color. Disable the color inside the logging message.\n");
1242 printf(" -e --log-level number. Set the global loglevel.\n");
1243 printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
1244 printf(" -V --version. Print the version of OpenBSC.\n");
1245}
1246
1247static void print_usage()
1248{
1249 printf("Usage: ipaccess-proxy\n");
1250}
1251
1252static void handle_options(int argc, char** argv)
1253{
1254 while (1) {
1255 int option_index = 0, c;
1256 static struct option long_options[] = {
1257 {"help", 0, 0, 'h'},
1258 {"disable-color", 0, 0, 's'},
1259 {"timestamp", 0, 0, 'T'},
1260 {"log-level", 1, 0, 'e'},
1261 {"listen", 1, 0, 'l'},
1262 {"bsc", 1, 0, 'b'},
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001263 {"udp", 1, 0, 'u'},
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001264 {0, 0, 0, 0}
1265 };
1266
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001267 c = getopt_long(argc, argv, "hsTe:l:b:g:",
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001268 long_options, &option_index);
1269 if (c == -1)
1270 break;
1271
1272 switch (c) {
1273 case 'h':
1274 print_usage();
1275 print_help();
1276 exit(0);
1277 case 'l':
1278 listen_ipaddr = optarg;
1279 break;
1280 case 'b':
1281 bsc_ipaddr = optarg;
1282 break;
Holger Hans Peter Freyther6147c5d2010-06-09 16:20:39 +08001283 case 'g':
1284 gprs_ns_ipaddr = optarg;
1285 break;
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001286 case 's':
1287 log_set_use_color(stderr_target, 0);
1288 break;
1289 case 'T':
1290 log_set_print_timestamp(stderr_target, 1);
1291 break;
1292 case 'e':
1293 log_set_log_level(stderr_target, atoi(optarg));
1294 break;
1295 default:
1296 /* ignore */
1297 break;
1298 }
1299 }
1300}
1301
Harald Welte2ca7c312009-12-23 22:44:04 +01001302int main(int argc, char **argv)
1303{
1304 int rc;
1305
1306 listen_ipaddr = "192.168.100.11";
1307 bsc_ipaddr = "192.168.100.239";
1308
1309 tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
1310
Harald Weltedc5062b2010-03-26 21:28:59 +08001311 log_init(&log_info);
1312 stderr_target = log_target_create_stderr();
1313 log_add_target(stderr_target);
1314 log_set_all_filter(stderr_target, 1);
1315 log_parse_category_mask(stderr_target, "DINP:DMI");
Harald Welte2ca7c312009-12-23 22:44:04 +01001316
Holger Hans Peter Freyther1a0c2b72010-06-09 14:59:09 +08001317 handle_options(argc, argv);
1318
Harald Welte2ca7c312009-12-23 22:44:04 +01001319 rc = ipaccess_proxy_setup();
1320 if (rc < 0)
1321 exit(1);
1322
1323 signal(SIGUSR1, &signal_handler);
1324 signal(SIGABRT, &signal_handler);
1325
1326 while (1) {
1327 bsc_select_main(0);
1328 }
1329}