blob: c6538ff620bac342a215960fdf2dfb27909a4095 [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 ipac_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
135{
136 u_int8_t t_len;
137 u_int8_t t_tag;
138 u_int8_t *cur = buf;
139
140 while (cur < buf + len) {
141 t_len = *cur++;
142 t_tag = *cur++;
143
Pablo Neira Ayusobdc90af2011-04-07 14:15:11 +0200144 DEBUGPC(DMI, "%s='%s' ", ipaccess_idtag_name(t_tag), cur);
Harald Welte48184982009-12-23 22:44:04 +0100145
146 dec->lv[t_tag].len = t_len;
147 dec->lv[t_tag].val = cur;
148
149 cur += t_len;
150 }
151 return 0;
152}
153
154static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
155 u_int16_t *trx_id)
156{
157 unsigned long ul;
158 char *endptr;
159 const char *nptr;
160
161 nptr = str;
162 ul = strtoul(nptr, &endptr, 10);
163 if (endptr <= nptr)
164 return -EINVAL;
165 if (site_id)
166 *site_id = ul & 0xffff;
167
168 if (*endptr++ != '/')
169 return -EINVAL;
170
171 nptr = endptr;
172 ul = strtoul(nptr, &endptr, 10);
173 if (endptr <= nptr)
174 return -EINVAL;
175 if (bts_id)
176 *bts_id = ul & 0xffff;
177
178 if (*endptr++ != '/')
179 return -EINVAL;
180
181 nptr = endptr;
182 ul = strtoul(nptr, &endptr, 10);
183 if (endptr <= nptr)
184 return -EINVAL;
185 if (trx_id)
186 *trx_id = ul & 0xffff;
187
188 return 0;
189}
190
191static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
192 u_int16_t site_id,
193 u_int16_t bts_id)
194{
195 struct ipa_bts_conn *ipbc;
196
197 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
198 if (ipbc->unit_id.site_id == site_id &&
199 ipbc->unit_id.bts_id == bts_id)
200 return ipbc;
201 }
202
203 return NULL;
204}
205
206struct ipa_proxy_conn *alloc_conn(void)
207{
208 struct ipa_proxy_conn *ipc;
209
210 ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
211 if (!ipc)
212 return NULL;
213
214 INIT_LLIST_HEAD(&ipc->tx_queue);
215
216 return ipc;
217}
218
219static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
220{
221 unsigned int i, len;
222
223 for (i = 0; i <= 0xff; i++) {
224 if (!TLVP_PRESENT(tlvp, i))
225 continue;
226
227 len = TLVP_LEN(tlvp, i);
228#if 0
229 if (!ipbc->id_tags[i])
230 ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
231 else
232#endif
Harald Welte7bc08d32009-12-23 23:35:51 +0100233 ipbc->id_tags[i] = talloc_realloc_size(ipbc,
Harald Welte48184982009-12-23 22:44:04 +0100234 ipbc->id_tags[i], len);
235 if (!ipbc->id_tags[i])
236 return -ENOMEM;
237
238 memset(ipbc->id_tags[i], 0, len);
239 //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
240 }
241 return 0;
242}
243
244
245static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
246
247#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
248
249static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
250 struct ipa_bts_conn *ipbc, u_int8_t trx_id)
251{
252 if (ipbc)
Harald Welte51d2a592010-03-26 21:28:59 +0800253 logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
Harald Welte48184982009-12-23 22:44:04 +0100254 ipbc->unit_id.bts_id, trx_id);
255 else
Harald Welte51d2a592010-03-26 21:28:59 +0800256 logp2(ss, lvl, file, line, 0, "unknown ");
Harald Welte48184982009-12-23 22:44:04 +0100257}
258
Harald Welte48184982009-12-23 22:44:04 +0100259static int handle_udp_read(struct bsc_fd *bfd)
260{
261 struct ipa_bts_conn *ipbc = bfd->data;
262 struct ipa_proxy_conn *other_conn = NULL;
263 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
264 struct ipaccess_head *hh;
265 int ret;
266
267 /* with UDP sockets, we cannot read partial packets but have to read
268 * all of it in one go */
269 hh = (struct ipaccess_head *) msg->data;
270 ret = recv(bfd->fd, msg->data, msg->data_len, 0);
271 if (ret < 0) {
Harald Weltea2be6862009-12-24 13:35:18 +0100272 if (errno != EAGAIN)
273 LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
Harald Welte48184982009-12-23 22:44:04 +0100274 msgb_free(msg);
275 return ret;
276 }
277 if (ret == 0) {
278 DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
279 bsc_unregister_fd(bfd);
280 close(bfd->fd);
281 bfd->fd = -1;
282 msgb_free(msg);
283 return -EIO;
284 }
285 if (ret < sizeof(*hh)) {
286 DEBUGP(DINP, "could not even read header!?!\n");
287 msgb_free(msg);
288 return -EIO;
289 }
290 msgb_put(msg, ret);
291 msg->l2h = msg->data + sizeof(*hh);
292 DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len));
293
294 if (hh->len != msg->len - sizeof(*hh)) {
295 DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
296 msg->len, msg->len - 3, hh->len);
297 msgb_free(msg);
298 return -EIO;
299 }
300
301 switch (bfd->priv_nr & 0xff) {
302 case UDP_TO_BTS:
303 /* injection towards BTS */
304 switch (hh->proto) {
305 case IPAC_PROTO_RSL:
306 /* FIXME: what to do about TRX > 0 */
307 other_conn = ipbc->rsl_conn[0];
308 break;
309 default:
310 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
311 "OML FD\n", hh->proto);
312 /* fall through */
313 case IPAC_PROTO_IPACCESS:
314 case IPAC_PROTO_OML:
315 other_conn = ipbc->oml_conn;
316 break;
317 }
318 break;
319 case UDP_TO_BSC:
320 /* injection towards BSC */
321 switch (hh->proto) {
322 case IPAC_PROTO_RSL:
323 /* FIXME: what to do about TRX > 0 */
324 other_conn = ipbc->bsc_rsl_conn[0];
325 break;
326 default:
327 DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
328 "OML FD\n", hh->proto);
329 case IPAC_PROTO_IPACCESS:
330 case IPAC_PROTO_OML:
331 other_conn = ipbc->bsc_oml_conn;
332 break;
333 }
334 break;
335 default:
336 DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
337 break;
338 }
339
340 if (other_conn) {
341 /* enqueue the message for TX on the respective FD */
342 msgb_enqueue(&other_conn->tx_queue, msg);
343 other_conn->fd.when |= BSC_FD_WRITE;
344 } else
345 msgb_free(msg);
346
347 return 0;
348}
349
350static int handle_udp_write(struct bsc_fd *bfd)
351{
352 /* not implemented yet */
353 bfd->when &= ~BSC_FD_WRITE;
354
355 return -EIO;
356}
357
358/* callback from select.c in case one of the fd's can be read/written */
359static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what)
360{
361 int rc = 0;
362
363 if (what & BSC_FD_READ)
364 rc = handle_udp_read(bfd);
365 if (what & BSC_FD_WRITE)
366 rc = handle_udp_write(bfd);
367
368 return rc;
369}
370
371
372static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd,
373 u_int16_t site_id, u_int16_t bts_id,
374 u_int16_t trx_id, struct tlv_parsed *tlvp,
375 struct msgb *msg)
376{
377 struct ipa_bts_conn *ipbc;
378 u_int16_t udp_port;
379 int ret = 0;
380 struct sockaddr_in sin;
381
382 memset(&sin, 0, sizeof(sin));
383 sin.sin_family = AF_INET;
384 inet_aton(bsc_ipaddr, &sin.sin_addr);
385
386 DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
387 site_id, bts_id, trx_id);
388
389 /* OML needs to be established before RSL */
390 if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
391 DEBUGPC(DINP, "Not a OML connection ?!?\n");
392 return -EIO;
393 }
394
395 /* allocate new BTS connection data structure */
396 ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
397 if (!ipbc) {
398 ret = -ENOMEM;
399 goto err_out;
400 }
401
402 DEBUGPC(DINP, "Created BTS Conn data structure\n");
403 ipbc->ipp = ipp;
404 ipbc->unit_id.site_id = site_id;
405 ipbc->unit_id.bts_id = bts_id;
406 ipbc->oml_conn = ipc;
407 ipc->bts_conn = ipbc;
408
409 /* store the content of the ID TAGS for later reference */
410 store_idtags(ipbc, tlvp);
411 ipbc->id_resp_len = msg->len;
412 ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
413 memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
414
415 /* Create OML TCP connection towards BSC */
Harald Welte9994b182009-12-23 22:47:53 +0100416 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte48184982009-12-23 22:44:04 +0100417 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
418 if (!ipbc->bsc_oml_conn) {
419 ret = -EIO;
420 goto err_bsc_conn;
421 }
422
423 DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
424 site_id, bts_id, trx_id);
425
426 /* Create UDP socket for BTS packet injection */
427 udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoa8bebcf2011-04-05 18:33:28 +0200428 ret = make_sock(&ipbc->udp_bts_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte48184982009-12-23 22:44:04 +0100429 UDP_TO_BTS, udp_fd_cb, ipbc);
430 if (ret < 0)
431 goto err_udp_bts;
432 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
433 "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
434
435 /* Create UDP socket for BSC packet injection */
436 udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
Pablo Neira Ayusoa8bebcf2011-04-05 18:33:28 +0200437 ret = make_sock(&ipbc->udp_bsc_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
Harald Welte48184982009-12-23 22:44:04 +0100438 UDP_TO_BSC, udp_fd_cb, ipbc);
439 if (ret < 0)
440 goto err_udp_bsc;
441 DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
442 "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800443
444
445 /* GPRS NS related code */
446 if (gprs_ns_ipaddr) {
447 struct sockaddr_in sock;
448 socklen_t len = sizeof(sock);
449 ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc);
450 if (ret < 0) {
451 LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
452 goto err_udp_bsc;
453 }
454
455 ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
456 ipbc->gprs_local_port = ntohs(sock.sin_port);
457 LOGP(DINP, LOGL_NOTICE,
458 "Created GPRS NS Socket. Listening on: %s:%d\n",
459 inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
460
461 ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
462 ipbc->bts_addr = sock.sin_addr;
463 }
464
Harald Welte48184982009-12-23 22:44:04 +0100465 llist_add(&ipbc->list, &ipp->bts_list);
466
467 return 0;
468
469err_udp_bsc:
470 bsc_unregister_fd(&ipbc->udp_bts_fd);
471err_udp_bts:
472 bsc_unregister_fd(&ipbc->bsc_oml_conn->fd);
473 close(ipbc->bsc_oml_conn->fd.fd);
474 talloc_free(ipbc->bsc_oml_conn);
475 ipbc->bsc_oml_conn = NULL;
476err_bsc_conn:
477 talloc_free(ipbc->id_resp);
478 talloc_free(ipbc);
479#if 0
480 bsc_unregister_fd(bfd);
481 close(bfd->fd);
482 talloc_free(bfd);
483#endif
484err_out:
485 return ret;
486}
487
488static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
489 struct bsc_fd *bfd)
490{
491 struct tlv_parsed tlvp;
492 u_int8_t msg_type = *(msg->l2h);
493 u_int16_t site_id, bts_id, trx_id;
494 struct ipa_bts_conn *ipbc;
495 int ret = 0;
496
497 switch (msg_type) {
498 case IPAC_MSGT_PING:
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200499 ret = ipaccess_send_pong(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100500 break;
501 case IPAC_MSGT_PONG:
502 DEBUGP(DMI, "PONG!\n");
503 break;
504 case IPAC_MSGT_ID_RESP:
505 DEBUGP(DMI, "ID_RESP ");
506 /* parse tags, search for Unit ID */
507 ipac_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
508 msgb_l2len(msg)-2);
509 DEBUGP(DMI, "\n");
510
511 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
512 LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
513 return -EIO;
514 }
515
516 /* lookup BTS, create sign_link, ... */
Holger Hans Peter Freyther7dd617a2010-03-30 15:20:46 +0200517 site_id = bts_id = trx_id = 0;
Harald Welte48184982009-12-23 22:44:04 +0100518 parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
519 &site_id, &bts_id, &trx_id);
520 ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
521 if (!ipbc) {
522 /* We have not found an ipbc (per-bts proxy instance)
523 * for this BTS yet. The first connection of a new BTS must
524 * be a OML connection. We allocate the associated data structures,
525 * and try to connect to the remote end */
526
527 return ipbc_alloc_connect(ipc, bfd, site_id, bts_id,
528 trx_id, &tlvp, msg);
529 /* if this fails, the caller will clean up bfd */
530 } else {
531 struct sockaddr_in sin;
532 memset(&sin, 0, sizeof(sin));
533 sin.sin_family = AF_INET;
534 inet_aton(bsc_ipaddr, &sin.sin_addr);
535
536 DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
537 site_id, bts_id, trx_id);
538
539 if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
540 LOGP(DINP, LOGL_ERROR, "Second OML connection from "
541 "same BTS ?!?\n");
542 return 0;
543 }
544
545 if (trx_id > MAX_TRX) {
546 LOGP(DINP, LOGL_ERROR, "We don't support more "
547 "than %u TRX\n", MAX_TRX);
548 return -EINVAL;
549 }
550
551 ipc->bts_conn = ipbc;
552 /* store TRX number in higher 8 bit of the bfd private number */
553 bfd->priv_nr |= trx_id << 8;
554 ipbc->rsl_conn[trx_id] = ipc;
555
556 /* Create RSL TCP connection towards BSC */
Harald Welte9994b182009-12-23 22:47:53 +0100557 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte48184982009-12-23 22:44:04 +0100558 ipbc->bsc_rsl_conn[trx_id] =
559 connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
560 if (!ipbc->bsc_oml_conn)
561 return -EIO;
562 DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
563 site_id, bts_id, trx_id);
564 }
565 break;
566 case IPAC_MSGT_ID_GET:
567 DEBUGP(DMI, "ID_GET\n");
568 if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
569 (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
570 DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
571 return -EIO;
572 }
573 ipbc = ipc->bts_conn;
574 if (!ipbc) {
575 DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
576 return -EIO;
577 }
578 ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
579 break;
580 case IPAC_MSGT_ID_ACK:
581 DEBUGP(DMI, "ID_ACK? -> ACK!\n");
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200582 ret = ipaccess_send_id_ack(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100583 break;
Holger Hans Peter Freyther667a90e2010-06-09 17:38:59 +0800584 default:
585 LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
586 return 1;
587 break;
Harald Welte48184982009-12-23 22:44:04 +0100588 }
589 return 0;
590}
591
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200592struct msgb *ipaccess_proxy_read_msg(struct bsc_fd *bfd, int *error)
Harald Welte48184982009-12-23 22:44:04 +0100593{
594 struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
595 struct ipaccess_head *hh;
596 int len, ret = 0;
597
598 if (!msg) {
599 *error = -ENOMEM;
600 return NULL;
601 }
602
603 /* first read our 3-byte header */
604 hh = (struct ipaccess_head *) msg->data;
605 ret = recv(bfd->fd, msg->data, 3, 0);
606 if (ret < 0) {
Harald Weltea2be6862009-12-24 13:35:18 +0100607 if (errno != EAGAIN)
Harald Welte16eac962009-12-24 12:49:43 +0100608 LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
Harald Welte48184982009-12-23 22:44:04 +0100609 msgb_free(msg);
610 *error = ret;
611 return NULL;
612 } else if (ret == 0) {
613 msgb_free(msg);
614 *error = ret;
615 return NULL;
616 }
617
618 msgb_put(msg, ret);
619
620 /* then read te length as specified in header */
621 msg->l2h = msg->data + sizeof(*hh);
622 len = ntohs(hh->len);
623 ret = recv(bfd->fd, msg->l2h, len, 0);
624 if (ret < len) {
625 LOGP(DINP, LOGL_ERROR, "short read!\n");
626 msgb_free(msg);
627 *error = -EIO;
628 return NULL;
629 }
630 msgb_put(msg, ret);
631
632 return msg;
633}
634
635static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
636 unsigned int priv_nr)
637{
638 struct ipa_proxy_conn *bsc_conn;
639 unsigned int trx_id = priv_nr >> 8;
640
641 switch (priv_nr & 0xff) {
642 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
643 bsc_conn = ipbc->bsc_oml_conn;
644 break;
645 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
646 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
647 break;
648 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
649 bsc_conn = ipbc->oml_conn;
650 break;
651 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
652 bsc_conn = ipbc->rsl_conn[trx_id];
653 break;
654 default:
655 bsc_conn = NULL;
656 break;
657 }
658 return bsc_conn;
659}
660
661static void reconn_tmr_cb(void *data)
662{
663 struct ipa_proxy *ipp = data;
664 struct ipa_bts_conn *ipbc;
665 struct sockaddr_in sin;
666 int i;
667
668 DEBUGP(DINP, "Running reconnect timer\n");
669
670 memset(&sin, 0, sizeof(sin));
671 sin.sin_family = AF_INET;
672 inet_aton(bsc_ipaddr, &sin.sin_addr);
673
674 llist_for_each_entry(ipbc, &ipp->bts_list, list) {
675 /* if OML to BSC is dead, try to restore it */
676 if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
Harald Welte9994b182009-12-23 22:47:53 +0100677 sin.sin_port = htons(IPA_TCP_PORT_OML);
Harald Welte48184982009-12-23 22:44:04 +0100678 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
679 LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
680 ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
681 if (!ipbc->bsc_oml_conn)
682 goto reschedule;
683 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
684 LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
685 }
686 /* if we (still) don't have a OML connection, skip RSL */
687 if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
688 continue;
689
690 for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
691 unsigned int priv_nr;
692 /* don't establish RSL links which we don't have */
693 if (!ipbc->rsl_conn[i])
694 continue;
695 if (ipbc->bsc_rsl_conn[i])
696 continue;
697 priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
698 priv_nr &= ~0xff;
699 priv_nr |= RSL_TO_BSC;
Harald Welte9994b182009-12-23 22:47:53 +0100700 sin.sin_port = htons(IPA_TCP_PORT_RSL);
Harald Welte48184982009-12-23 22:44:04 +0100701 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
702 LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
703 ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
704 if (!ipbc->bsc_rsl_conn)
705 goto reschedule;
706 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
707 LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
708 }
709 }
710 return;
711
712reschedule:
713 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
714}
715
716static void handle_dead_socket(struct bsc_fd *bfd)
717{
718 struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
719 struct ipa_proxy_conn *bsc_conn; /* remote conn */
720 struct ipa_bts_conn *ipbc = ipc->bts_conn;
721 unsigned int trx_id = bfd->priv_nr >> 8;
722 struct msgb *msg, *msg2;
723
724 bsc_unregister_fd(bfd);
725 close(bfd->fd);
726 bfd->fd = -1;
727
728 /* FIXME: clear tx_queue, remove all references, etc. */
729 llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
730 msgb_free(msg);
731
732 switch (bfd->priv_nr & 0xff) {
733 case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
Pablo Neira Ayuso83f40d12011-03-27 21:31:48 +0200734 /* The BTS started a connection with us but we got no
735 * IPAC_MSGT_ID_RESP message yet, in that scenario we did not
736 * allocate the ipa_bts_conn structure. */
737 if (ipbc == NULL)
738 break;
Harald Welte48184982009-12-23 22:44:04 +0100739 ipbc->oml_conn = NULL;
740 bsc_conn = ipbc->bsc_oml_conn;
741 /* close the connection to the BSC */
742 bsc_unregister_fd(&bsc_conn->fd);
743 close(bsc_conn->fd.fd);
744 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
745 msgb_free(msg);
746 talloc_free(bsc_conn);
747 ipbc->bsc_oml_conn = NULL;
748 /* FIXME: do we need to delete the entire ipbc ? */
749 break;
750 case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
751 ipbc->rsl_conn[trx_id] = NULL;
752 bsc_conn = ipbc->bsc_rsl_conn[trx_id];
753 /* close the connection to the BSC */
754 bsc_unregister_fd(&bsc_conn->fd);
755 close(bsc_conn->fd.fd);
756 llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
757 msgb_free(msg);
758 talloc_free(bsc_conn);
759 ipbc->bsc_rsl_conn[trx_id] = NULL;
760 break;
761 case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
762 ipbc->bsc_oml_conn = NULL;
763 bsc_conn = ipbc->oml_conn;
764 /* start reconnect timer */
765 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
766 break;
767 case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
768 ipbc->bsc_rsl_conn[trx_id] = NULL;
769 bsc_conn = ipbc->rsl_conn[trx_id];
770 /* start reconnect timer */
771 bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
772 break;
773 default:
774 bsc_conn = NULL;
775 break;
776 }
777
778 talloc_free(ipc);
779}
780
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800781static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg)
782{
783 uint8_t *nsvci;
784
785 if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC)
786 return;
787
788 if (msgb_l2len(msg) != 39)
789 return;
790
791 /*
792 * Check if this is a IPA Set Attribute or IPA Set Attribute ACK
793 * and if the FOM Class is GPRS NSVC0 and then we will patch it.
794 *
795 * The patch assumes the message looks like the one from the trace
796 * but we only match messages with a specific size anyway... So
797 * this hack should work just fine.
798 */
799
800 if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
801 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
802 msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800803 nsvci = &msg->l2h[23];
804 ipbc->gprs_orig_port = *(u_int16_t *)(nsvci+8);
805 ipbc->gprs_orig_ip = *(u_int32_t *)(nsvci+10);
806 *(u_int16_t *)(nsvci+8) = htons(ipbc->gprs_local_port);
807 *(u_int32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr;
808 } else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
809 msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
810 msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800811 nsvci = &msg->l2h[23];
812 *(u_int16_t *)(nsvci+8) = ipbc->gprs_orig_port;
813 *(u_int32_t *)(nsvci+10) = ipbc->gprs_orig_ip;
814 }
815}
816
Harald Welte48184982009-12-23 22:44:04 +0100817static int handle_tcp_read(struct bsc_fd *bfd)
818{
819 struct ipa_proxy_conn *ipc = bfd->data;
820 struct ipa_bts_conn *ipbc = ipc->bts_conn;
821 struct ipa_proxy_conn *bsc_conn;
Harald Welte7bc08d32009-12-23 23:35:51 +0100822 struct msgb *msg;
Harald Welte48184982009-12-23 22:44:04 +0100823 struct ipaccess_head *hh;
824 int ret = 0;
825 char *btsbsc;
826
Harald Welte48184982009-12-23 22:44:04 +0100827 if ((bfd->priv_nr & 0xff) <= 2)
828 btsbsc = "BTS";
829 else
830 btsbsc = "BSC";
831
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200832 msg = ipaccess_proxy_read_msg(bfd, &ret);
Harald Welte48184982009-12-23 22:44:04 +0100833 if (!msg) {
834 if (ret == 0) {
835 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
836 LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
837 "dead socket\n", btsbsc);
838 handle_dead_socket(bfd);
839 }
840 return ret;
841 }
842
843 msgb_put(msg, ret);
844 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
845 DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
846
847 hh = (struct ipaccess_head *) msg->data;
848 if (hh->proto == IPAC_PROTO_IPACCESS) {
849 ret = ipaccess_rcvmsg(ipc, msg, bfd);
850 if (ret < 0) {
851 bsc_unregister_fd(bfd);
852 close(bfd->fd);
853 bfd->fd = -1;
854 talloc_free(bfd);
Holger Hans Peter Freyther667a90e2010-06-09 17:38:59 +0800855 msgb_free(msg);
856 return ret;
857 } else if (ret == 0) {
858 /* we do not forward parts of the CCM protocol
859 * through the proxy but rather terminate it ourselves. */
860 msgb_free(msg);
861 return ret;
Harald Welte48184982009-12-23 22:44:04 +0100862 }
Harald Welte48184982009-12-23 22:44:04 +0100863 }
864
865 if (!ipbc) {
866 LOGP(DINP, LOGL_ERROR,
867 "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
868 msgb_free(msg);
869 return -EIO;
870 }
871
872 bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
873 if (bsc_conn) {
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +0800874 if (gprs_ns_ipaddr)
875 patch_gprs_msg(ipbc, bfd->priv_nr, msg);
Harald Welte48184982009-12-23 22:44:04 +0100876 /* enqueue packet towards BSC */
877 msgb_enqueue(&bsc_conn->tx_queue, msg);
878 /* mark respective filedescriptor as 'we want to write' */
879 bsc_conn->fd.when |= BSC_FD_WRITE;
880 } else {
881 logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
882 LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
883 "since remote connection is dead\n", btsbsc);
884 msgb_free(msg);
885 }
886
887 return ret;
888}
889
890/* a TCP socket is ready to be written to */
891static int handle_tcp_write(struct bsc_fd *bfd)
892{
893 struct ipa_proxy_conn *ipc = bfd->data;
894 struct ipa_bts_conn *ipbc = ipc->bts_conn;
895 struct llist_head *lh;
896 struct msgb *msg;
897 char *btsbsc;
898 int ret;
899
900 if ((bfd->priv_nr & 0xff) <= 2)
901 btsbsc = "BTS";
902 else
903 btsbsc = "BSC";
904
905
906 /* get the next msg for this timeslot */
907 if (llist_empty(&ipc->tx_queue)) {
908 bfd->when &= ~BSC_FD_WRITE;
909 return 0;
910 }
911 lh = ipc->tx_queue.next;
912 llist_del(lh);
913 msg = llist_entry(lh, struct msgb, list);
914
915 logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
916 DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
917 hexdump(msg->data, msg->len));
918
919 ret = send(bfd->fd, msg->data, msg->len, 0);
920 msgb_free(msg);
921
922 if (ret == 0) {
923 logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
924 LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
925 handle_dead_socket(bfd);
926 }
927
928 return ret;
929}
930
931/* callback from select.c in case one of the fd's can be read/written */
932static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
933{
934 int rc = 0;
935
936 if (what & BSC_FD_READ) {
937 rc = handle_tcp_read(bfd);
938 if (rc < 0)
939 return rc;
940 }
941 if (what & BSC_FD_WRITE)
942 rc = handle_tcp_write(bfd);
943
944 return rc;
945}
946
947/* callback of the listening filedescriptor */
948static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
949{
950 int ret;
951 struct ipa_proxy_conn *ipc;
952 struct bsc_fd *bfd;
953 struct sockaddr_in sa;
954 socklen_t sa_len = sizeof(sa);
955
956 if (!(what & BSC_FD_READ))
957 return 0;
958
959 ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
960 if (ret < 0) {
961 perror("accept");
962 return ret;
963 }
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200964 DEBUGP(DINP, "accept()ed new %s link from %s\n",
Harald Welte48184982009-12-23 22:44:04 +0100965 (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
966 inet_ntoa(sa.sin_addr));
967
968 ipc = alloc_conn();
969 if (!ipc) {
970 close(ret);
971 return -ENOMEM;
972 }
973
974 bfd = &ipc->fd;
975 bfd->fd = ret;
976 bfd->data = ipc;
977 bfd->priv_nr = listen_bfd->priv_nr;
978 bfd->cb = ipaccess_fd_cb;
979 bfd->when = BSC_FD_READ;
980 ret = bsc_register_fd(bfd);
981 if (ret < 0) {
982 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
983 close(bfd->fd);
984 talloc_free(ipc);
985 return ret;
986 }
987
988 /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
Pablo Neira Ayusob6a229e2011-04-07 14:15:06 +0200989 ret = ipaccess_send_id_req(bfd->fd);
Harald Welte48184982009-12-23 22:44:04 +0100990
991 return 0;
992}
993
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +0800994static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
995{
996 int ret;
997 struct sockaddr_in addr;
998 socklen_t len = sizeof(addr);
999 memset(&addr, 0, sizeof(addr));
1000
1001 addr.sin_family = AF_INET;
Holger Hans Peter Freytherc6adead2010-06-10 15:56:26 +08001002 addr.sin_port = htons(port);
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001003 addr.sin_addr = ip;
1004
1005 ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
1006 if (ret < 0) {
1007 LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
1008 }
1009}
1010
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001011static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what)
1012{
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001013 struct ipa_bts_conn *bts;
1014 char buf[4096];
1015 int ret;
1016 struct sockaddr_in sock;
1017 socklen_t len = sizeof(sock);
1018
1019 /* 1. get the data... */
1020 ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
1021 if (ret < 0) {
1022 LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
1023 return -1;
1024 }
1025
1026 bts = bfd->data;
1027
1028 /* 2. figure out where to send it to */
1029 if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
1030 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
1031 send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
1032 } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
1033 LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
1034 send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
Holger Hans Peter Freytherc6adead2010-06-10 15:56:26 +08001035 } else {
1036 LOGP(DINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001037 }
1038
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001039 return 0;
1040}
1041
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001042static 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 +08001043{
1044 struct sockaddr_in addr;
1045 int ret;
1046
1047 bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1048 bfd->cb = cb;
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001049 bfd->data = data;
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001050 bfd->when = BSC_FD_READ;
1051
1052 memset(&addr, 0, sizeof(addr));
1053 addr.sin_family = AF_INET;
1054 addr.sin_port = 0;
1055 inet_aton(listen_ipaddr, &addr.sin_addr);
1056
1057 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
1058 if (ret < 0) {
1059 LOGP(DINP, LOGL_ERROR,
1060 "Could not bind n socket for IP %s with error: %s.\n",
1061 listen_ipaddr, strerror(errno));
1062 return -EIO;
1063 }
1064
1065 ret = bsc_register_fd(bfd);
1066 if (ret < 0) {
1067 perror("register_listen_fd");
1068 return ret;
1069 }
1070 return 0;
1071}
1072
Harald Welte48184982009-12-23 22:44:04 +01001073/* Actively connect to a BSC. */
1074static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
1075{
1076 struct ipa_proxy_conn *ipc;
1077 struct bsc_fd *bfd;
1078 int ret, on = 1;
1079
1080 ipc = alloc_conn();
1081 if (!ipc)
1082 return NULL;
1083
1084 ipc->bts_conn = data;
1085
1086 bfd = &ipc->fd;
1087 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1088 bfd->cb = ipaccess_fd_cb;
1089 bfd->when = BSC_FD_READ | BSC_FD_WRITE;
1090 bfd->data = ipc;
1091 bfd->priv_nr = priv_nr;
1092
1093 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1094
1095 ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
1096 if (ret < 0) {
Holger Hans Peter Freytherbf0bb1b2010-06-09 15:15:11 +08001097 LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
1098 inet_ntoa(sa->sin_addr));
Harald Welte48184982009-12-23 22:44:04 +01001099 close(bfd->fd);
1100 talloc_free(ipc);
1101 return NULL;
1102 }
1103
1104 /* pre-fill tx_queue with identity request */
1105 ret = bsc_register_fd(bfd);
1106 if (ret < 0) {
1107 close(bfd->fd);
1108 talloc_free(ipc);
1109 return NULL;
1110 }
1111
1112 return ipc;
1113}
1114
1115static int ipaccess_proxy_setup(void)
1116{
1117 int ret;
1118
1119 ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
1120 if (!ipp)
1121 return -ENOMEM;
1122 INIT_LLIST_HEAD(&ipp->bts_list);
1123 ipp->reconn_timer.cb = reconn_tmr_cb;
1124 ipp->reconn_timer.data = ipp;
1125
1126 /* Listen for OML connections */
Pablo Neira Ayusoc650d022011-04-07 14:15:02 +02001127 ret = make_sock(&ipp->oml_listen_fd, IPPROTO_TCP, INADDR_ANY,
1128 IPA_TCP_PORT_OML, OML_FROM_BTS, listen_fd_cb, NULL);
Harald Welte48184982009-12-23 22:44:04 +01001129 if (ret < 0)
1130 return ret;
1131
1132 /* Listen for RSL connections */
Pablo Neira Ayusoc650d022011-04-07 14:15:02 +02001133 ret = make_sock(&ipp->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY,
1134 IPA_TCP_PORT_RSL, RSL_FROM_BTS, listen_fd_cb, NULL);
Harald Welte48184982009-12-23 22:44:04 +01001135
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001136 if (ret < 0)
1137 return ret;
1138
1139 /* Connect the GPRS NS Socket */
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +08001140 if (gprs_ns_ipaddr) {
Holger Hans Peter Freytherb3f0bfa2010-06-09 17:07:43 +08001141 inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
Holger Hans Peter Freythera07016f2010-06-10 15:57:08 +08001142 inet_aton(listen_ipaddr, &ipp->listen_addr);
1143 }
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001144
Harald Welte48184982009-12-23 22:44:04 +01001145 return ret;
1146}
1147
1148static void signal_handler(int signal)
1149{
1150 fprintf(stdout, "signal %u received\n", signal);
1151
1152 switch (signal) {
1153 case SIGABRT:
1154 /* in case of abort, we want to obtain a talloc report
1155 * and then return to the caller, who will abort the process */
1156 case SIGUSR1:
1157 talloc_report_full(tall_bsc_ctx, stderr);
1158 break;
1159 default:
1160 break;
1161 }
1162}
1163
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001164static void print_help()
1165{
1166 printf(" ipaccess-proxy is a proxy BTS.\n");
1167 printf(" -h --help. This help text.\n");
1168 printf(" -l --listen IP. The ip to listen to.\n");
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001169 printf(" -b --bsc IP. The BSC IP address.\n");
1170 printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
1171 printf("\n");
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001172 printf(" -s --disable-color. Disable the color inside the logging message.\n");
1173 printf(" -e --log-level number. Set the global loglevel.\n");
1174 printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
1175 printf(" -V --version. Print the version of OpenBSC.\n");
1176}
1177
1178static void print_usage()
1179{
1180 printf("Usage: ipaccess-proxy\n");
1181}
1182
1183static void handle_options(int argc, char** argv)
1184{
1185 while (1) {
1186 int option_index = 0, c;
1187 static struct option long_options[] = {
1188 {"help", 0, 0, 'h'},
1189 {"disable-color", 0, 0, 's'},
1190 {"timestamp", 0, 0, 'T'},
1191 {"log-level", 1, 0, 'e'},
1192 {"listen", 1, 0, 'l'},
1193 {"bsc", 1, 0, 'b'},
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001194 {"udp", 1, 0, 'u'},
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001195 {0, 0, 0, 0}
1196 };
1197
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001198 c = getopt_long(argc, argv, "hsTe:l:b:g:",
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001199 long_options, &option_index);
1200 if (c == -1)
1201 break;
1202
1203 switch (c) {
1204 case 'h':
1205 print_usage();
1206 print_help();
1207 exit(0);
1208 case 'l':
1209 listen_ipaddr = optarg;
1210 break;
1211 case 'b':
1212 bsc_ipaddr = optarg;
1213 break;
Holger Hans Peter Freyther4f2a3742010-06-09 16:20:39 +08001214 case 'g':
1215 gprs_ns_ipaddr = optarg;
1216 break;
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001217 case 's':
1218 log_set_use_color(stderr_target, 0);
1219 break;
1220 case 'T':
1221 log_set_print_timestamp(stderr_target, 1);
1222 break;
1223 case 'e':
1224 log_set_log_level(stderr_target, atoi(optarg));
1225 break;
1226 default:
1227 /* ignore */
1228 break;
1229 }
1230 }
1231}
1232
Harald Welte48184982009-12-23 22:44:04 +01001233int main(int argc, char **argv)
1234{
1235 int rc;
1236
1237 listen_ipaddr = "192.168.100.11";
1238 bsc_ipaddr = "192.168.100.239";
1239
1240 tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
1241
Harald Welte51d2a592010-03-26 21:28:59 +08001242 log_init(&log_info);
1243 stderr_target = log_target_create_stderr();
1244 log_add_target(stderr_target);
1245 log_set_all_filter(stderr_target, 1);
1246 log_parse_category_mask(stderr_target, "DINP:DMI");
Harald Welte48184982009-12-23 22:44:04 +01001247
Holger Hans Peter Freytherda41bd42010-06-09 14:59:09 +08001248 handle_options(argc, argv);
1249
Harald Welte48184982009-12-23 22:44:04 +01001250 rc = ipaccess_proxy_setup();
1251 if (rc < 0)
1252 exit(1);
1253
1254 signal(SIGUSR1, &signal_handler);
1255 signal(SIGABRT, &signal_handler);
1256
1257 while (1) {
1258 bsc_select_main(0);
1259 }
1260}