blob: 56f1548cb85828f2615f96ddb2025847ffc2463c [file] [log] [blame]
Harald Welte0df904d2018-12-03 11:00:04 +01001/* (C) 2018-2019 by sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Harald Welte, Philipp Maier
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <osmocom/msc/sgs_iface.h>
22#include <osmocom/msc/debug.h>
23#include <osmocom/msc/sgs_server.h>
24#include <osmocom/core/utils.h>
25#include <osmocom/core/socket.h>
26#include <osmocom/core/select.h>
27#include <osmocom/netif/stream.h>
28#include <netinet/sctp.h>
29
30#define LOGSGC(sgc, lvl, fmt, args...) \
31 LOGP(DSGS, lvl, "%s: " fmt, (sgc)->sockname, ## args)
32
33/* call-back when data arrives on SGs */
34static int sgs_conn_readable_cb(struct osmo_stream_srv *conn)
35{
36 struct osmo_fd *ofd = osmo_stream_srv_get_ofd(conn);
37 struct sgs_connection *sgc = osmo_stream_srv_get_data(conn);
38 struct msgb *msg = gsm29118_msgb_alloc();
39 struct sctp_sndrcvinfo sinfo;
40 int flags = 0;
41 int rc;
42
43 /* we cannot use osmo_stream_srv_recv() here, as we might get some out-of-band info from
44 * SCTP. FIXME: add something like osmo_stream_srv_recv_sctp() to libosmo-netif and use
45 * it here as well as in libosmo-sigtran */
46 rc = sctp_recvmsg(ofd->fd, msgb_data(msg), msgb_tailroom(msg), NULL, NULL, &sinfo, &flags);
47 if (rc < 0) {
48 osmo_stream_srv_destroy(conn);
49 rc = -EBADF;
50 goto out;
51 } else if (rc == 0) {
52 osmo_stream_srv_destroy(conn);
53 rc = -EBADF;
54 goto out;
55 } else {
56 msgb_put(msg, rc);
57 }
58
59 if (flags & MSG_NOTIFICATION) {
60 union sctp_notification *notif = (union sctp_notification *)msgb_data(msg);
61
62 switch (notif->sn_header.sn_type) {
63 case SCTP_SHUTDOWN_EVENT:
64 osmo_stream_srv_destroy(conn);
65 rc = -EBADF;
66 break;
67 case SCTP_ASSOC_CHANGE:
68 /* FIXME: do we have to notify the SGs code about this? */
69 break;
70 default:
71 break;
72 }
73 rc = 0;
74 goto out;
75 }
76
77 /* set l2 header, as that's what we use in SGs code */
78 msg->l2h = msgb_data(msg);
79
80 if (msgb_sctp_ppid(msg) != 0) {
81 LOGSGC(sgc, LOGL_NOTICE, "Ignoring SCTP PPID %ld (spec violation)\n", msgb_sctp_ppid(msg));
82 msgb_free(msg);
83 return 0;
84 }
85
86 /* handle message */
87 sgs_iface_rx(sgc, msg);
88
89 return 0;
90out:
91 msgb_free(msg);
92 return rc;
93}
94
95/* call-back when new connection is closed ed on SGs */
96static int sgs_conn_closed_cb(struct osmo_stream_srv *conn)
97{
98 struct sgs_connection *sgc = osmo_stream_srv_get_data(conn);
99
100 LOGSGC(sgc, LOGL_NOTICE, "Connection lost\n");
101 if (sgc->mme) {
102 /* unlink ourselves from the MME context */
103 if (sgc->mme->conn == sgc)
104 sgc->mme->conn = NULL;
105 }
106 llist_del(&sgc->entry);
107 return 0;
108}
109
110/* call-back when new connection is accept() ed on SGs */
111static int sgs_accept_cb(struct osmo_stream_srv_link *link, int fd)
112{
113 struct sgs_state *sgs = osmo_stream_srv_link_get_data(link);
114 struct sgs_connection *sgc = talloc_zero(link, struct sgs_connection);
115 OSMO_ASSERT(sgc);
116 sgc->sgs = sgs;
117 osmo_sock_get_name_buf(sgc->sockname, sizeof(sgc->sockname), fd);
118 sgc->srv = osmo_stream_srv_create(sgc, link, fd, sgs_conn_readable_cb, sgs_conn_closed_cb, sgc);
119 if (!sgc->srv) {
120 talloc_free(sgc);
121 return -1;
122 }
123 LOGSGC(sgc, LOGL_INFO, "Accepted new SGs connection\n");
124 llist_add_tail(&sgc->entry, &sgs->conn_list);
125
126 return 0;
127}
128
129static struct sgs_state *sgs_state_alloc(void *ctx)
130{
131 struct sgs_state *sgs = talloc_zero(ctx, struct sgs_state);
132
133 INIT_LLIST_HEAD(&sgs->mme_list);
134 INIT_LLIST_HEAD(&sgs->conn_list);
135
136 memcpy(sgs->cfg.timer, sgs_state_timer_defaults, sizeof(sgs->cfg.timer));
137 memcpy(sgs->cfg.counter, sgs_state_counter_defaults, sizeof(sgs->cfg.counter));
138 sgs->cfg.local_port = SGS_PORT_DEFAULT;
139 osmo_strlcpy(sgs->cfg.local_addr, DEFAULT_SGS_SERVER_IP, sizeof(sgs->cfg.local_addr));
140 osmo_strlcpy(sgs->cfg.vlr_name, DEFAULT_SGS_SERVER_VLR_NAME, sizeof(sgs->cfg.vlr_name));
141
142 return sgs;
143}
144
145/*! allocate SGs new sgs state
146 * \param[in] ctx talloc context
147 * \returns returns allocated sgs state, NULL in case of error. */
148struct sgs_state *sgs_server_alloc(void *ctx)
149{
150 struct sgs_state *sgs;
151 struct osmo_stream_srv_link *link;
152
153 sgs = sgs_state_alloc(ctx);
154 if (!sgs)
155 return NULL;
156
157 sgs->srv_link = link = osmo_stream_srv_link_create(ctx);
158 if (!sgs->srv_link)
159 return NULL;
160
161 osmo_stream_srv_link_set_nodelay(link, true);
162 osmo_stream_srv_link_set_addr(link, sgs->cfg.local_addr);
163 osmo_stream_srv_link_set_port(link, sgs->cfg.local_port);
164 osmo_stream_srv_link_set_proto(link, IPPROTO_SCTP);
165 osmo_stream_srv_link_set_data(link, sgs);
166 osmo_stream_srv_link_set_accept_cb(link, sgs_accept_cb);
167
168 return sgs;
169}
170
171/*! (re)open SGs interface (SCTP)
172 * \param[in] sgs associated sgs state
173 * \returns 0 in case of success, -EINVAL in case of error. */
174int sgs_server_open(struct sgs_state *sgs)
175{
176 int rc;
177 struct osmo_fd *ofd = osmo_stream_srv_link_get_ofd(sgs->srv_link);
178
179 rc = osmo_stream_srv_link_open(sgs->srv_link);
180 if (rc < 0) {
181 LOGP(DSGS, LOGL_ERROR, "SGs socket cannot be opened: %s\n", strerror(errno));
182 return -EINVAL;
183 }
184
185 LOGP(DSGS, LOGL_NOTICE, "SGs socket bound to %s\n", osmo_sock_get_name2(ofd->fd));
186 return 0;
187}