diff options
Diffstat (limited to 'openbsc/src/ipaccess')
-rw-r--r-- | openbsc/src/ipaccess/ipaccess-proxy.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c index 0a7b18b47..56e910111 100644 --- a/openbsc/src/ipaccess/ipaccess-proxy.c +++ b/openbsc/src/ipaccess/ipaccess-proxy.c @@ -55,13 +55,12 @@ struct ipa_proxy { struct bsc_fd oml_listen_fd; /* socket where we listen for incoming RSL from BTS */ struct bsc_fd rsl_listen_fd; - /* socket where we get the GPRS NS data */ - struct bsc_fd gprs_ns_fd; - int gprs_port; /* list of BTS's (struct ipa_bts_conn */ struct llist_head bts_list; /* the BSC reconnect timer */ struct timer_list reconn_timer; + /* global GPRS NS data */ + struct in_addr gprs_addr; }; /* global pointer to the proxy structure */ @@ -72,7 +71,6 @@ struct ipa_proxy_conn { struct llist_head tx_queue; struct ipa_bts_conn *bts_conn; }; - #define MAX_TRX 4 /* represents a particular BTS in our proxy */ @@ -99,6 +97,11 @@ struct ipa_bts_conn { struct bsc_fd udp_bts_fd; struct bsc_fd udp_bsc_fd; + /* NS data */ + struct in_addr bts_addr; + struct bsc_fd gprs_ns_fd; + int gprs_local_port; + char *id_tags[0xff]; u_int8_t *id_resp; unsigned int id_resp_len; @@ -120,6 +123,9 @@ static char *listen_ipaddr; static char *bsc_ipaddr; static char *gprs_ns_ipaddr; +static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *); +static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what); + #define PROXY_ALLOC_SIZE 1200 static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG }; @@ -501,6 +507,28 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd, goto err_udp_bsc; DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection " "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port); + + + /* GPRS NS related code */ + if (gprs_ns_ipaddr) { + struct sockaddr_in sock; + socklen_t len = sizeof(sock); + ret = make_gprs_sock(&ipbc->gprs_ns_fd, gprs_ns_cb, ipbc); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n"); + goto err_udp_bsc; + } + + ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len); + ipbc->gprs_local_port = ntohs(sock.sin_port); + LOGP(DINP, LOGL_NOTICE, + "Created GPRS NS Socket. Listening on: %s:%d\n", + inet_ntoa(sock.sin_addr), ipbc->gprs_local_port); + + ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len); + ipbc->bts_addr = sock.sin_addr; + } + llist_add(&ipbc->list, &ipp->bts_list); return 0; @@ -986,8 +1014,49 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } +static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port) +{ + int ret; + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_port = port; + addr.sin_addr = ip; + + ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n"); + } +} + static int gprs_ns_cb(struct bsc_fd *bfd, unsigned int what) { + struct ipa_bts_conn *bts; + char buf[4096]; + int ret; + struct sockaddr_in sock; + socklen_t len = sizeof(sock); + + /* 1. get the data... */ + ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno)); + return -1; + } + + bts = bfd->data; + + /* 2. figure out where to send it to */ + if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) { + LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n"); + send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000); + } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) { + LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n"); + send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000); + } + return 0; } @@ -1034,13 +1103,14 @@ static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr, return 0; } -static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int)) +static int make_gprs_sock(struct bsc_fd *bfd, int (*cb)(struct bsc_fd*,unsigned int), void *data) { struct sockaddr_in addr; int ret; bfd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); bfd->cb = cb; + bfd->data = data; bfd->when = BSC_FD_READ; memset(&addr, 0, sizeof(addr)); @@ -1131,21 +1201,8 @@ static int ipaccess_proxy_setup(void) return ret; /* Connect the GPRS NS Socket */ - if (gprs_ns_ipaddr) { - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - ret = make_gprs_sock(&ipp->gprs_ns_fd, gprs_ns_cb); - if (ret < 0) - return ret; - - ret = getsockname(ipp->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len); - if (ret < 0) - return ret; - ipp->gprs_port = ntohs(sock.sin_port); - LOGP(DINP, LOGL_NOTICE, - "Created GPRS NS Socket. Listening on: %s:%d\n", - inet_ntoa(sock.sin_addr), ipp->gprs_port); - } + if (gprs_ns_ipaddr) + inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr); return ret; } |