blob: d2bf599ed90b5f36c8b1bd2b5e243d5decbddffe [file] [log] [blame]
Harald Welte48184982009-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 Freyther51808442010-10-06 20:37:09 +08004 * (C) 2010 by On-Waves
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08005 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte48184982009-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 Welte0e3e88e2011-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 Welte48184982009-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 Welte0e3e88e2011-01-01 15:25:50 +010017 * GNU Affero General Public License for more details.
Harald Welte48184982009-12-23 22:44:04 +010018 *
Harald Welte0e3e88e2011-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 Welte48184982009-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 Freytherda41bd42010-06-09 14:59:09 +080038#define _GNU_SOURCE
39#include <getopt.h>
40
Harald Welte48184982009-12-23 22:44:04 +010041#include <openbsc/gsm_data.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/select.h>
43#include <osmocom/gsm/tlv.h>
44#include <osmocom/core/msgb.h>
Harald Welte48184982009-12-23 22:44:04 +010045#include <openbsc/debug.h>
46#include <openbsc/ipaccess.h>
Pablo Neira Ayusoa8bebcf2011-04-05 18:33:28 +020047#include <openbsc/socket.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010048#include <osmocom/core/talloc.h>
Harald Welte48184982009-12-23 22:44:04 +010049
Harald Welte51d2a592010-03-26 21:28:59 +080050static struct log_target *stderr_target;
Harald Welte48184982009-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 Freytherb3f0bfa2010-06-09 17:07:43 +080062 /* global GPRS NS data */
63 struct in_addr gprs_addr;
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +080064 struct in_addr listen_addr;
Harald Welte48184982009-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 Welte48184982009-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 Freytherb3f0bfa2010-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 Freythera07016f2010-06-10 15:57:08 +0800105 uint16_t gprs_orig_port;
106 uint32_t gprs_orig_ip;
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800107
Harald Welte48184982009-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 Freyther4f2a3742010-06-09 16:20:39 +0800127static char *gprs_ns_ipaddr;
Harald Welte48184982009-12-23 22:44:04 +0100128
Holger Hans Peter Freytherb3f0bfa2010-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 Freytherd92d1962010-06-09 14:39:22 +0800132#define PROXY_ALLOC_SIZE 1200
Harald Welte48184982009-12-23 22:44:04 +0100133
Harald Welte48184982009-12-23 22:44:04 +0100134static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
135 u_int16_t *trx_id)
136{
137 unsigned long ul;
138 char *endptr;
139 const char *nptr;
140
141 nptr = str;
142 ul = strtoul(nptr, &endptr, 10);
143 if (endptr <= nptr)
144 return -EINVAL;
145 if (site_id)
146 *site_id = ul & 0xffff;
147
148 if (*endptr++ != '/')
149 return -EINVAL;
150
151 nptr = endptr;
152 ul = strtoul(nptr, &endptr, 10);
153 if (endptr <= nptr)
154 return -EINVAL;
155 if (bts_id)
156 *bts_id = ul & 0xffff;
157
158 if (*endptr++ != '/')
159 return -EINVAL;
160
161 nptr = endptr;
162 ul = strtoul(nptr, &endptr, 10);
163 if (endptr <= nptr)
164 return -EINVAL;
165 if (trx_id)
166 *trx_id = ul & 0xffff;
167
168 return 0;
169}
170
171static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
172 u_int16_t site_id,
173 u_int16_t bts_id)
174{
175 struct ipa_bts_conn *ipbc;
176
177 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
178 if (ipbc->unit_id.site_id == site_id &&
179 ipbc->unit_id.bts_id == bts_id)
180 return ipbc;
181 }
182
183 return NULL;
184}
185
186struct ipa_proxy_conn *alloc_conn(void)
187{
188 struct ipa_proxy_conn *ipc;
189
190 ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
191 if (!ipc)
192 return NULL;
193
194 INIT_LLIST_HEAD(&ipc->tx_queue);
195
196 return ipc;
197}
198
199static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
200{
201 unsigned int i, len;
202
203 for (i = 0; i <= 0xff; i++) {
204 if (!TLVP_PRESENT(tlvp, i))
205 continue;
206
207 len = TLVP_LEN(tlvp, i);
208#if 0
209 if (!ipbc->id_tags[i])
210 ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
211 else
212#endif
Harald Welte7bc08d32009-12-23 23:35:51 +0100213 ipbc->id_tags[i] = talloc_realloc_size(ipbc,
Harald Welte48184982009-12-23 22:44:04 +0100214 ipbc->id_tags[i], len);
215 if (!ipbc->id_tags[i])
216 return -ENOMEM;
217
218 memset(ipbc->id_tags[i], 0, len);
219 //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
220 }
221 return 0;
222}
223
224
225static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
226
227#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
228
229static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
230 struct ipa_bts_conn *ipbc, u_int8_t trx_id)
231{
232 if (ipbc)
Harald Welte51d2a592010-03-26 21:28:59 +0800233 logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
Harald Welte48184982009-12-23 22:44:04 +0100234 ipbc->unit_id.bts_id, trx_id);
235 else
Harald Welte51d2a592010-03-26 21:28:59 +0800236 logp2(ss, lvl, file, line, 0, "unknown ");
Harald Welte48184982009-12-23 22:44:04 +0100237}
238
Harald Welte48184982009-12-23 22:44:04 +0100239static int handle_udp_read(struct bsc_fd *bfd)
240{
241 struct ipa_bts_conn *ipbc = bfd->data;
242 struct ipa_proxy_conn *other_conn = NULL;
243 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
244 struct ipaccess_head *hh;
245 int ret;
246
247 /* with UDP sockets, we cannot read partial packets but have to read
248 * all of it in one go */
249 hh = (struct ipaccess_head *) msg->data;
250 ret = recv(bfd->fd, msg->data, msg->data_len, 0);
251 if (ret < 0) {
Harald Weltea2be6862009-12-24 13:35:18 +0100252 if (errno != EAGAIN)
253 LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
Harald Welte48184982009-12-23 22:44:04 +0100254 msgb_free(msg);
255 return ret;
256 }
257 if (ret == 0) {
258 DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
259 bsc_unregister_fd(bfd);
260 close(bfd->fd);
261 bfd->fd = -1;
262 msgb_free(msg);
263 return -EIO;
264 }
265 if (ret < sizeof(*hh)) {
266 DEBUGP(DINP, "could not even read header!?!\n");
267 msgb_free(msg);
268 return -EIO;
269 }
270 msgb_put(msg, ret);
271 msg->l2h = msg->data + sizeof(*hh);
272 DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len));
273
274 if (hh->len != msg->len - sizeof(*hh)) {
275 DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
276 msg->len, msg->len - 3, hh->len);
277 msgb_free(msg);
278 return -EIO;
279 }
280
281 switch (bfd->priv_nr & 0xff) {
282 case UDP_TO_BTS:
283 /* injection towards BTS */
284 switch (hh->proto) {
285 case IPAC_PROTO_RSL:
286 /* FIXME: what to do about TRX > 0 */
287 other_conn = ipbc->rsl_conn[0];
288 break;
289 default:
290 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
291 "OML FD\n", hh->proto);
292 /* fall through */
293 case IPAC_PROTO_IPACCESS:
294 case IPAC_PROTO_OML:
295 other_conn = ipbc->oml_conn;
296 break;
297 }
298 break;
299 case UDP_TO_BSC:
300 /* injection towards BSC */
301 switch (hh->proto) {
302 case IPAC_PROTO_RSL:
303 /* FIXME: what to do about TRX > 0 */
304 other_conn = ipbc->bsc_rsl_conn[0];
305 break;
306 default:
307 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
308 "OML FD\n", hh->proto);
309 case IPAC_PROTO_IPACCESS:
310 case IPAC_PROTO_OML:
311 other_conn = ipbc->bsc_oml_conn;
312 break;
313 }
314 break;
315 default:
316 DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
317 break;
318 }
319
320 if (other_conn) {
321 /* enqueue the message for TX on the respective FD */
322 msgb_enqueue(&other_conn->tx_queue, msg);
323 other_conn->fd.when |= BSC_FD_WRITE;
324 } else
325 msgb_free(msg);
326
327 return 0;
328}
329
330static int handle_udp_write(struct bsc_fd *bfd)
331{
332 /* not implemented yet */
333 bfd->when &= ~BSC_FD_WRITE;
334
335 return -EIO;
336}
337
338/* callback from select.c in case one of the fd's can be read/written */
339static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what)
340{
341 int rc = 0;
342
343 if (what & BSC_FD_READ)
344 rc = handle_udp_read(bfd);
345 if (what & BSC_FD_WRITE)
346 rc = handle_udp_write(bfd);
347
348 return rc;
349}
350
351
352static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd,
353 u_int16_t site_id, u_int16_t bts_id,
354 u_int16_t trx_id, struct tlv_parsed *tlvp,
355 struct msgb *msg)
356{
357 struct ipa_bts_conn *ipbc;
358 u_int16_t udp_port;
359 int ret = 0;
360 struct sockaddr_in sin;
361
362 memset(&sin, 0, sizeof(sin));
363 sin.sin_family = AF_INET;
364 inet_aton(bsc_ipaddr, &sin.sin_addr);
365
366 DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
367 site_id, bts_id, trx_id);
368
369 /* OML needs to be established before RSL */
370 if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
371 DEBUGPC(DINP, "Not a OML connection ?!?\n");
372 return -EIO;
373 }
374
375 /* allocate new BTS connection data structure */
376 ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
377 if (!ipbc) {
378 ret = -ENOMEM;
379 goto err_out;
380 }
381
382 DEBUGPC(DINP, "Created BTS Conn data structure\n");
383 ipbc->ipp = ipp;
384 ipbc->unit_id.site_id = site_id;
385 ipbc->unit_id.bts_id = bts_id;
386 ipbc->oml_conn = ipc;
387 ipc->bts_conn = ipbc;
388
389 /* store the content of the ID TAGS for later reference */
390 store_idtags(ipbc, tlvp);
391 ipbc->id_resp_len = msg->len;
392 ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
393 memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
394
395 /* Create OML TCP connection towards BSC */
Harald Welte9994b182009-12-23 22:47:53 +0100396 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte48184982009-12-23 22:44:04 +0100397 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
398 if (!ipbc->bsc_oml_conn) {
399 ret = -EIO;
400 goto err_bsc_conn;
401 }
402
403 DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
404 site_id, bts_id, trx_id);
405
406 /* Create UDP socket for BTS packet injection */
407 udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoa8bebcf2011-04-05 18:33:28 +0200408 ret = make_sock(&ipbc->udp_bts_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte48184982009-12-23 22:44:04 +0100409 UDP_TO_BTS, udp_fd_cb, ipbc);
410 if (ret < 0)
411 goto err_udp_bts;
412 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
413 "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
414
415 /* Create UDP socket for BSC packet injection */
416 udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoa8bebcf2011-04-05 18:33:28 +0200417 ret = make_sock(&ipbc->udp_bsc_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte48184982009-12-23 22:44:04 +0100418 UDP_TO_BSC, udp_fd_cb, ipbc);
419 if (ret < 0)
420 goto err_udp_bsc;
421 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
422 "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800423
424
425 /* GPRS NS related code */
426 if (gprs_ns_ipaddr) {
427 struct sockaddr_in sock;
428 socklen_t len = sizeof(sock);
429 ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc);
430 if (ret < 0) {
431 LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
432 goto err_udp_bsc;
433 }
434
435 ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
436 ipbc->gprs_local_port = ntohs(sock.sin_port);
437 LOGP(DINP, LOGL_NOTICE,
438 "Created GPRS NS Socket. Listening on: %s:%d\n",
439 inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
440
441 ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
442 ipbc->bts_addr = sock.sin_addr;
443 }
444
Harald Welte48184982009-12-23 22:44:04 +0100445 llist_add(&ipbc->list, &ipp->bts_list);
446
447 return 0;
448
449err_udp_bsc:
450 bsc_unregister_fd(&ipbc->udp_bts_fd);
451err_udp_bts:
452 bsc_unregister_fd(&ipbc->bsc_oml_conn->fd);
453 close(ipbc->bsc_oml_conn->fd.fd);
454 talloc_free(ipbc->bsc_oml_conn);
455 ipbc->bsc_oml_conn = NULL;
456err_bsc_conn:
457 talloc_free(ipbc->id_resp);
458 talloc_free(ipbc);
459#if 0
460 bsc_unregister_fd(bfd);
461 close(bfd->fd);
462 talloc_free(bfd);
463#endif
464err_out:
465 return ret;
466}
467
468static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
469 struct bsc_fd *bfd)
470{
471 struct tlv_parsed tlvp;
472 u_int8_t msg_type = *(msg->l2h);
473 u_int16_t site_id, bts_id, trx_id;
474 struct ipa_bts_conn *ipbc;
475 int ret = 0;
476
477 switch (msg_type) {
478 case IPAC_MSGT_PING:
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200479 ret = ipaccess_send_pong(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100480 break;
481 case IPAC_MSGT_PONG:
482 DEBUGP(DMI, "PONG!\n");
483 break;
484 case IPAC_MSGT_ID_RESP:
485 DEBUGP(DMI, "ID_RESP ");
486 /* parse tags, search for Unit ID */
Pablo Neira Ayusof914f222011-04-07 14:15:16 +0200487 ipaccess_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
488 msgb_l2len(msg)-2);
Harald Welte48184982009-12-23 22:44:04 +0100489 DEBUGP(DMI, "\n");
490
491 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
492 LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
493 return -EIO;
494 }
495
496 /* lookup BTS, create sign_link, ... */
Holger Hans Peter Freyther7dd617a2010-03-30 15:20:46 +0200497 site_id = bts_id = trx_id = 0;
Harald Welte48184982009-12-23 22:44:04 +0100498 parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
499 &site_id, &bts_id, &trx_id);
500 ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
501 if (!ipbc) {
502 /* We have not found an ipbc (per-bts proxy instance)
503 * for this BTS yet. The first connection of a new BTS must
504 * be a OML connection. We allocate the associated data structures,
505 * and try to connect to the remote end */
506
507 return ipbc_alloc_connect(ipc, bfd, site_id, bts_id,
508 trx_id, &tlvp, msg);
509 /* if this fails, the caller will clean up bfd */
510 } else {
511 struct sockaddr_in sin;
512 memset(&sin, 0, sizeof(sin));
513 sin.sin_family = AF_INET;
514 inet_aton(bsc_ipaddr, &sin.sin_addr);
515
516 DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
517 site_id, bts_id, trx_id);
518
519 if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
520 LOGP(DINP, LOGL_ERROR, "Second OML connection from "
521 "same BTS ?!?\n");
522 return 0;
523 }
524
525 if (trx_id > MAX_TRX) {
526 LOGP(DINP, LOGL_ERROR, "We don't support more "
527 "than %u TRX\n", MAX_TRX);
528 return -EINVAL;
529 }
530
531 ipc->bts_conn = ipbc;
532 /* store TRX number in higher 8 bit of the bfd private number */
533 bfd->priv_nr |= trx_id << 8;
534 ipbc->rsl_conn[trx_id] = ipc;
535
536 /* Create RSL TCP connection towards BSC */
Harald Welte9994b182009-12-23 22:47:53 +0100537 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte48184982009-12-23 22:44:04 +0100538 ipbc->bsc_rsl_conn[trx_id] =
539 connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
540 if (!ipbc->bsc_oml_conn)
541 return -EIO;
542 DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
543 site_id, bts_id, trx_id);
544 }
545 break;
546 case IPAC_MSGT_ID_GET:
547 DEBUGP(DMI, "ID_GET\n");
548 if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
549 (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
550 DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
551 return -EIO;
552 }
553 ipbc = ipc->bts_conn;
554 if (!ipbc) {
555 DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
556 return -EIO;
557 }
558 ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
559 break;
560 case IPAC_MSGT_ID_ACK:
561 DEBUGP(DMI, "ID_ACK? -> ACK!\n");
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200562 ret = ipaccess_send_id_ack(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100563 break;
Holger Hans Peter Freyther667a90e2010-06-09 17:38:59 +0800564 default:
565 LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
566 return 1;
567 break;
Harald Welte48184982009-12-23 22:44:04 +0100568 }
569 return 0;
570}
571
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200572struct msgb *ipaccess_proxy_read_msg(struct bsc_fd *bfd, int *error)
Harald Welte48184982009-12-23 22:44:04 +0100573{
574 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
575 struct ipaccess_head *hh;
576 int len, ret = 0;
577
578 if (!msg) {
579 *error = -ENOMEM;
580 return NULL;
581 }
582
583 /* first read our 3-byte header */
584 hh = (struct ipaccess_head *) msg->data;
585 ret = recv(bfd->fd, msg->data, 3, 0);
586 if (ret < 0) {
Harald Weltea2be6862009-12-24 13:35:18 +0100587 if (errno != EAGAIN)
Harald Welte16eac962009-12-24 12:49:43 +0100588 LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
Harald Welte48184982009-12-23 22:44:04 +0100589 msgb_free(msg);
590 *error = ret;
591 return NULL;
592 } else if (ret == 0) {
593 msgb_free(msg);
594 *error = ret;
595 return NULL;
596 }
597
598 msgb_put(msg, ret);
599
600 /* then read te length as specified in header */
601 msg->l2h = msg->data + sizeof(*hh);
602 len = ntohs(hh->len);
603 ret = recv(bfd->fd, msg->l2h, len, 0);
604 if (ret < len) {
605 LOGP(DINP, LOGL_ERROR, "short read!\n");
606 msgb_free(msg);
607 *error = -EIO;
608 return NULL;
609 }
610 msgb_put(msg, ret);
611
612 return msg;
613}
614
615static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
616 unsigned int priv_nr)
617{
618 struct ipa_proxy_conn *bsc_conn;
619 unsigned int trx_id = priv_nr >> 8;
620
621 switch (priv_nr & 0xff) {
622 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
623 bsc_conn = ipbc->bsc_oml_conn;
624 break;
625 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
626 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
627 break;
628 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
629 bsc_conn = ipbc->oml_conn;
630 break;
631 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
632 bsc_conn = ipbc->rsl_conn[trx_id];
633 break;
634 default:
635 bsc_conn = NULL;
636 break;
637 }
638 return bsc_conn;
639}
640
641static void reconn_tmr_cb(void *data)
642{
643 struct ipa_proxy *ipp = data;
644 struct ipa_bts_conn *ipbc;
645 struct sockaddr_in sin;
646 int i;
647
648 DEBUGP(DINP, "Running reconnect timer\n");
649
650 memset(&sin, 0, sizeof(sin));
651 sin.sin_family = AF_INET;
652 inet_aton(bsc_ipaddr, &sin.sin_addr);
653
654 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
655 /* if OML to BSC is dead, try to restore it */
656 if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
Harald Welte9994b182009-12-23 22:47:53 +0100657 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte48184982009-12-23 22:44:04 +0100658 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
659 LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
660 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
661 if (!ipbc->bsc_oml_conn)
662 goto reschedule;
663 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
664 LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
665 }
666 /* if we (still) don't have a OML connection, skip RSL */
667 if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
668 continue;
669
670 for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
671 unsigned int priv_nr;
672 /* don't establish RSL links which we don't have */
673 if (!ipbc->rsl_conn[i])
674 continue;
675 if (ipbc->bsc_rsl_conn[i])
676 continue;
677 priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
678 priv_nr &= ~0xff;
679 priv_nr |= RSL_TO_BSC;
Harald Welte9994b182009-12-23 22:47:53 +0100680 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte48184982009-12-23 22:44:04 +0100681 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
682 LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
683 ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
684 if (!ipbc->bsc_rsl_conn)
685 goto reschedule;
686 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
687 LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
688 }
689 }
690 return;
691
692reschedule:
693 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
694}
695
696static void handle_dead_socket(struct bsc_fd *bfd)
697{
698 struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
699 struct ipa_proxy_conn *bsc_conn; /* remote conn */
700 struct ipa_bts_conn *ipbc = ipc->bts_conn;
701 unsigned int trx_id = bfd->priv_nr >> 8;
702 struct msgb *msg, *msg2;
703
704 bsc_unregister_fd(bfd);
705 close(bfd->fd);
706 bfd->fd = -1;
707
708 /* FIXME: clear tx_queue, remove all references, etc. */
709 llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
710 msgb_free(msg);
711
712 switch (bfd->priv_nr & 0xff) {
713 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
Pablo Neira Ayuso83f40d12011-03-27 21:31:48 +0200714 /* The BTS started a connection with us but we got no
715 * IPAC_MSGT_ID_RESP message yet, in that scenario we did not
716 * allocate the ipa_bts_conn structure. */
717 if (ipbc == NULL)
718 break;
Harald Welte48184982009-12-23 22:44:04 +0100719 ipbc->oml_conn = NULL;
720 bsc_conn = ipbc->bsc_oml_conn;
721 /* close the connection to the BSC */
722 bsc_unregister_fd(&bsc_conn->fd);
723 close(bsc_conn->fd.fd);
724 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
725 msgb_free(msg);
726 talloc_free(bsc_conn);
727 ipbc->bsc_oml_conn = NULL;
728 /* FIXME: do we need to delete the entire ipbc ? */
729 break;
730 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
731 ipbc->rsl_conn[trx_id] = NULL;
732 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
733 /* close the connection to the BSC */
734 bsc_unregister_fd(&bsc_conn->fd);
735 close(bsc_conn->fd.fd);
736 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
737 msgb_free(msg);
738 talloc_free(bsc_conn);
739 ipbc->bsc_rsl_conn[trx_id] = NULL;
740 break;
741 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
742 ipbc->bsc_oml_conn = NULL;
743 bsc_conn = ipbc->oml_conn;
744 /* start reconnect timer */
745 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
746 break;
747 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
748 ipbc->bsc_rsl_conn[trx_id] = NULL;
749 bsc_conn = ipbc->rsl_conn[trx_id];
750 /* start reconnect timer */
751 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
752 break;
753 default:
754 bsc_conn = NULL;
755 break;
756 }
757
758 talloc_free(ipc);
759}
760
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800761static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg)
762{
763 uint8_t *nsvci;
764
765 if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC)
766 return;
767
768 if (msgb_l2len(msg) != 39)
769 return;
770
771 /*
772 * Check if this is a IPA Set Attribute or IPA Set Attribute ACK
773 * and if the FOM Class is GPRS NSVC0 and then we will patch it.
774 *
775 * The patch assumes the message looks like the one from the trace
776 * but we only match messages with a specific size anyway... So
777 * this hack should work just fine.
778 */
779
780 if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
781 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
782 msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800783 nsvci = &msg->l2h[23];
784 ipbc->gprs_orig_port = *(u_int16_t *)(nsvci+8);
785 ipbc->gprs_orig_ip = *(u_int32_t *)(nsvci+10);
786 *(u_int16_t *)(nsvci+8) = htons(ipbc->gprs_local_port);
787 *(u_int32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr;
788 } else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
789 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
790 msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800791 nsvci = &msg->l2h[23];
792 *(u_int16_t *)(nsvci+8) = ipbc->gprs_orig_port;
793 *(u_int32_t *)(nsvci+10) = ipbc->gprs_orig_ip;
794 }
795}
796
Harald Welte48184982009-12-23 22:44:04 +0100797static int handle_tcp_read(struct bsc_fd *bfd)
798{
799 struct ipa_proxy_conn *ipc = bfd->data;
800 struct ipa_bts_conn *ipbc = ipc->bts_conn;
801 struct ipa_proxy_conn *bsc_conn;
Harald Welte7bc08d32009-12-23 23:35:51 +0100802 struct msgb *msg;
Harald Welte48184982009-12-23 22:44:04 +0100803 struct ipaccess_head *hh;
804 int ret = 0;
805 char *btsbsc;
806
Harald Welte48184982009-12-23 22:44:04 +0100807 if ((bfd->priv_nr & 0xff) <= 2)
808 btsbsc = "BTS";
809 else
810 btsbsc = "BSC";
811
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200812 msg = ipaccess_proxy_read_msg(bfd, &ret);
Harald Welte48184982009-12-23 22:44:04 +0100813 if (!msg) {
814 if (ret == 0) {
815 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
816 LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
817 "dead socket\n", btsbsc);
818 handle_dead_socket(bfd);
819 }
820 return ret;
821 }
822
823 msgb_put(msg, ret);
824 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
825 DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
826
827 hh = (struct ipaccess_head *) msg->data;
828 if (hh->proto == IPAC_PROTO_IPACCESS) {
829 ret = ipaccess_rcvmsg(ipc, msg, bfd);
830 if (ret < 0) {
831 bsc_unregister_fd(bfd);
832 close(bfd->fd);
833 bfd->fd = -1;
834 talloc_free(bfd);
Holger Hans Peter Freyther667a90e2010-06-09 17:38:59 +0800835 msgb_free(msg);
836 return ret;
837 } else if (ret == 0) {
838 /* we do not forward parts of the CCM protocol
839 * through the proxy but rather terminate it ourselves. */
840 msgb_free(msg);
841 return ret;
Harald Welte48184982009-12-23 22:44:04 +0100842 }
Harald Welte48184982009-12-23 22:44:04 +0100843 }
844
845 if (!ipbc) {
846 LOGP(DINP, LOGL_ERROR,
847 "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
848 msgb_free(msg);
849 return -EIO;
850 }
851
852 bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
853 if (bsc_conn) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800854 if (gprs_ns_ipaddr)
855 patch_gprs_msg(ipbc, bfd->priv_nr, msg);
Harald Welte48184982009-12-23 22:44:04 +0100856 /* enqueue packet towards BSC */
857 msgb_enqueue(&bsc_conn->tx_queue, msg);
858 /* mark respective filedescriptor as 'we want to write' */
859 bsc_conn->fd.when |= BSC_FD_WRITE;
860 } else {
861 logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
862 LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
863 "since remote connection is dead\n", btsbsc);
864 msgb_free(msg);
865 }
866
867 return ret;
868}
869
870/* a TCP socket is ready to be written to */
871static int handle_tcp_write(struct bsc_fd *bfd)
872{
873 struct ipa_proxy_conn *ipc = bfd->data;
874 struct ipa_bts_conn *ipbc = ipc->bts_conn;
875 struct llist_head *lh;
876 struct msgb *msg;
877 char *btsbsc;
878 int ret;
879
880 if ((bfd->priv_nr & 0xff) <= 2)
881 btsbsc = "BTS";
882 else
883 btsbsc = "BSC";
884
885
886 /* get the next msg for this timeslot */
887 if (llist_empty(&ipc->tx_queue)) {
888 bfd->when &= ~BSC_FD_WRITE;
889 return 0;
890 }
891 lh = ipc->tx_queue.next;
892 llist_del(lh);
893 msg = llist_entry(lh, struct msgb, list);
894
895 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
896 DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
897 hexdump(msg->data, msg->len));
898
899 ret = send(bfd->fd, msg->data, msg->len, 0);
900 msgb_free(msg);
901
902 if (ret == 0) {
903 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
904 LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
905 handle_dead_socket(bfd);
906 }
907
908 return ret;
909}
910
911/* callback from select.c in case one of the fd's can be read/written */
912static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
913{
914 int rc = 0;
915
916 if (what & BSC_FD_READ) {
917 rc = handle_tcp_read(bfd);
918 if (rc < 0)
919 return rc;
920 }
921 if (what & BSC_FD_WRITE)
922 rc = handle_tcp_write(bfd);
923
924 return rc;
925}
926
927/* callback of the listening filedescriptor */
928static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
929{
930 int ret;
931 struct ipa_proxy_conn *ipc;
932 struct bsc_fd *bfd;
933 struct sockaddr_in sa;
934 socklen_t sa_len = sizeof(sa);
935
936 if (!(what & BSC_FD_READ))
937 return 0;
938
939 ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
940 if (ret < 0) {
941 perror("accept");
942 return ret;
943 }
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200944 DEBUGP(DINP, "accept()ed new %s link from %s\n",
Harald Welte48184982009-12-23 22:44:04 +0100945 (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
946 inet_ntoa(sa.sin_addr));
947
948 ipc = alloc_conn();
949 if (!ipc) {
950 close(ret);
951 return -ENOMEM;
952 }
953
954 bfd = &ipc->fd;
955 bfd->fd = ret;
956 bfd->data = ipc;
957 bfd->priv_nr = listen_bfd->priv_nr;
958 bfd->cb = ipaccess_fd_cb;
959 bfd->when = BSC_FD_READ;
960 ret = bsc_register_fd(bfd);
961 if (ret < 0) {
962 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
963 close(bfd->fd);
964 talloc_free(ipc);
965 return ret;
966 }
967
968 /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200969 ret = ipaccess_send_id_req(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100970
971 return 0;
972}
973
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800974static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
975{
976 int ret;
977 struct sockaddr_in addr;
978 socklen_t len = sizeof(addr);
979 memset(&addr, 0, sizeof(addr));
980
981 addr.sin_family = AF_INET;
Holger Hans Peter Freytherc6adead2010-06-10 15:56:26 +0800982 addr.sin_port = htons(port);
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800983 addr.sin_addr = ip;
984
985 ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
986 if (ret < 0) {
987 LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
988 }
989}
990
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +0800991static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
992{
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800993 struct ipa_bts_conn *bts;
994 char buf[4096];
995 int ret;
996 struct sockaddr_in sock;
997 socklen_t len = sizeof(sock);
998
999 /* 1. get the data... */
1000 ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
1001 if (ret < 0) {
1002 LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
1003 return -1;
1004 }
1005
1006 bts = bfd->data;
1007
1008 /* 2. figure out where to send it to */
1009 if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
1010 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
1011 send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
1012 } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
1013 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
1014 send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
Holger Hans Peter Freytherc6adead2010-06-10 15:56:26 +08001015 } else {
1016 LOGP(DINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001017 }
1018
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001019 return 0;
1020}
1021
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001022static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *data)
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001023{
1024 struct sockaddr_in addr;
1025 int ret;
1026
1027 bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1028 bfd->cb = cb;
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001029 bfd->data = data;
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001030 bfd->when = BSC_FD_READ;
1031
1032 memset(&addr, 0, sizeof(addr));
1033 addr.sin_family = AF_INET;
1034 addr.sin_port = 0;
1035 inet_aton(listen_ipaddr, &addr.sin_addr);
1036
1037 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1038 if (ret < 0) {
1039 LOGP(DINP, LOGL_ERROR,
1040 "Could not bind n socket for IP %s with error: %s.\n",
1041 listen_ipaddr, strerror(errno));
1042 return -EIO;
1043 }
1044
1045 ret = bsc_register_fd(bfd);
1046 if (ret < 0) {
1047 perror("register_listen_fd");
1048 return ret;
1049 }
1050 return 0;
1051}
1052
Harald Welte48184982009-12-23 22:44:04 +01001053/* Actively connect to a BSC. */
1054static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
1055{
1056 struct ipa_proxy_conn *ipc;
1057 struct bsc_fd *bfd;
1058 int ret, on = 1;
1059
1060 ipc = alloc_conn();
1061 if (!ipc)
1062 return NULL;
1063
1064 ipc->bts_conn = data;
1065
1066 bfd = &ipc->fd;
1067 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1068 bfd->cb = ipaccess_fd_cb;
1069 bfd->when = BSC_FD_READ | BSC_FD_WRITE;
1070 bfd->data = ipc;
1071 bfd->priv_nr = priv_nr;
1072
1073 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1074
1075 ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
1076 if (ret < 0) {
Holger Hans Peter Freytherbf0bb1b2010-06-09 15:15:11 +08001077 LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
1078 inet_ntoa(sa->sin_addr));
Harald Welte48184982009-12-23 22:44:04 +01001079 close(bfd->fd);
1080 talloc_free(ipc);
1081 return NULL;
1082 }
1083
1084 /* pre-fill tx_queue with identity request */
1085 ret = bsc_register_fd(bfd);
1086 if (ret < 0) {
1087 close(bfd->fd);
1088 talloc_free(ipc);
1089 return NULL;
1090 }
1091
1092 return ipc;
1093}
1094
1095static int ipaccess_proxy_setup(void)
1096{
1097 int ret;
1098
1099 ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
1100 if (!ipp)
1101 return -ENOMEM;
1102 INIT_LLIST_HEAD(&ipp->bts_list);
1103 ipp->reconn_timer.cb = reconn_tmr_cb;
1104 ipp->reconn_timer.data = ipp;
1105
1106 /* Listen for OML connections */
Pablo Neira Ayusoc650d022011-04-07 14:15:02 +02001107 ret = make_sock(&ipp->oml_listen_fd, IPPROTO_TCP, INADDR_ANY,
1108 IPA_TCP_PORT_OML, OML_FROM_BTS, listen_fd_cb, NULL);
Harald Welte48184982009-12-23 22:44:04 +01001109 if (ret < 0)
1110 return ret;
1111
1112 /* Listen for RSL connections */
Pablo Neira Ayusoc650d022011-04-07 14:15:02 +02001113 ret = make_sock(&ipp->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY,
1114 IPA_TCP_PORT_RSL, RSL_FROM_BTS, listen_fd_cb, NULL);
Harald Welte48184982009-12-23 22:44:04 +01001115
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001116 if (ret < 0)
1117 return ret;
1118
1119 /* Connect the GPRS NS Socket */
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +08001120 if (gprs_ns_ipaddr) {
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001121 inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +08001122 inet_aton(listen_ipaddr, &ipp->listen_addr);
1123 }
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001124
Harald Welte48184982009-12-23 22:44:04 +01001125 return ret;
1126}
1127
1128static void signal_handler(int signal)
1129{
1130 fprintf(stdout, "signal %u received\n", signal);
1131
1132 switch (signal) {
1133 case SIGABRT:
1134 /* in case of abort, we want to obtain a talloc report
1135 * and then return to the caller, who will abort the process */
1136 case SIGUSR1:
1137 talloc_report_full(tall_bsc_ctx, stderr);
1138 break;
1139 default:
1140 break;
1141 }
1142}
1143
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001144static void print_help()
1145{
1146 printf(" ipaccess-proxy is a proxy BTS.\n");
1147 printf(" -h --help. This help text.\n");
1148 printf(" -l --listen IP. The ip to listen to.\n");
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001149 printf(" -b --bsc IP. The BSC IP address.\n");
1150 printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
1151 printf("\n");
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001152 printf(" -s --disable-color. Disable the color inside the logging message.\n");
1153 printf(" -e --log-level number. Set the global loglevel.\n");
1154 printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
1155 printf(" -V --version. Print the version of OpenBSC.\n");
1156}
1157
1158static void print_usage()
1159{
1160 printf("Usage: ipaccess-proxy\n");
1161}
1162
1163static void handle_options(int argc, char** argv)
1164{
1165 while (1) {
1166 int option_index = 0, c;
1167 static struct option long_options[] = {
1168 {"help", 0, 0, 'h'},
1169 {"disable-color", 0, 0, 's'},
1170 {"timestamp", 0, 0, 'T'},
1171 {"log-level", 1, 0, 'e'},
1172 {"listen", 1, 0, 'l'},
1173 {"bsc", 1, 0, 'b'},
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001174 {"udp", 1, 0, 'u'},
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001175 {0, 0, 0, 0}
1176 };
1177
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001178 c = getopt_long(argc, argv, "hsTe:l:b:g:",
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001179 long_options, &option_index);
1180 if (c == -1)
1181 break;
1182
1183 switch (c) {
1184 case 'h':
1185 print_usage();
1186 print_help();
1187 exit(0);
1188 case 'l':
1189 listen_ipaddr = optarg;
1190 break;
1191 case 'b':
1192 bsc_ipaddr = optarg;
1193 break;
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001194 case 'g':
1195 gprs_ns_ipaddr = optarg;
1196 break;
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001197 case 's':
1198 log_set_use_color(stderr_target, 0);
1199 break;
1200 case 'T':
1201 log_set_print_timestamp(stderr_target, 1);
1202 break;
1203 case 'e':
1204 log_set_log_level(stderr_target, atoi(optarg));
1205 break;
1206 default:
1207 /* ignore */
1208 break;
1209 }
1210 }
1211}
1212
Harald Welte48184982009-12-23 22:44:04 +01001213int main(int argc, char **argv)
1214{
1215 int rc;
1216
1217 listen_ipaddr = "192.168.100.11";
1218 bsc_ipaddr = "192.168.100.239";
1219
1220 tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
1221
Harald Welte51d2a592010-03-26 21:28:59 +08001222 log_init(&log_info);
1223 stderr_target = log_target_create_stderr();
1224 log_add_target(stderr_target);
1225 log_set_all_filter(stderr_target, 1);
1226 log_parse_category_mask(stderr_target, "DINP:DMI");
Harald Welte48184982009-12-23 22:44:04 +01001227
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001228 handle_options(argc, argv);
1229
Harald Welte48184982009-12-23 22:44:04 +01001230 rc = ipaccess_proxy_setup();
1231 if (rc < 0)
1232 exit(1);
1233
1234 signal(SIGUSR1, &signal_handler);
1235 signal(SIGABRT, &signal_handler);
1236
1237 while (1) {
1238 bsc_select_main(0);
1239 }
1240}