blob: 390dc1cab9130db8809a8ab0c5359165dc5f0e13 [file] [log] [blame]
Neels Hofmeyr3243c7c2018-09-30 05:01:20 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* IuUP Core Network side protocol handling, minimal implementation */
3
4/*
5 * (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
6 * All Rights Reserved
7 *
8 * Author: Neels Hofmeyr <neels@hofmeyr.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <talloc.h>
26#include <errno.h>
27#include <string.h>
28#include <arpa/inet.h>
29
30#include <osmocom/core/utils.h>
31#include <osmocom/core/logging.h>
32#include <osmocom/core/msgb.h>
33
34#include <osmocom/netif/rtp.h>
35
36#include <osmocom/mgcp/iuup_cn_node.h>
37#include <osmocom/mgcp/iuup_protocol.h>
38
39#include <osmocom/mgcp/debug.h>
40
41#define LOG_IUUP_CN(cn, level, fmt, args...) \
42 LOGP(DRTP, level, "(%s) " fmt, (cn)->name, ## args)
43
44struct osmo_iuup_cn {
45 struct osmo_iuup_cn_cfg cfg;
46 char *name;
47 uint8_t next_frame_nr;
48};
49
50struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
51 const char *name_fmt, ...)
52{
53 va_list ap;
54 struct osmo_iuup_cn *cn = talloc_zero(ctx, struct osmo_iuup_cn);
55 OSMO_ASSERT(cn);
56
57 cn->cfg = *cfg;
58
59 if (!name_fmt)
60 name_fmt = "-";
61
62 va_start(ap, name_fmt);
63 cn->name = talloc_vasprintf(cn, name_fmt, ap);
64 va_end(ap);
65
66 if (!osmo_identifier_valid(cn->name)) {
67 LOGP(DLGLOBAL, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
68 osmo_quote_str(cn->name, -1));
69 talloc_free(cn);
70 return NULL;
71 }
72
73 return cn;
74}
75
76void osmo_iuup_cn_free(struct osmo_iuup_cn *cn)
77{
78 talloc_free(cn);
79}
80
81static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,
82 struct osmo_iuup_hdr_data *hdr, void *pdu_priv)
83{
84 /* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */
85 unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;
86 memmove(pdu->data + sizeof(*hdr), pdu->data, pre_hdr_len);
87
88 msgb_pull(pdu, sizeof(*hdr));
89
90 cn->cfg.rx_payload(pdu, cn->cfg.node_priv, pdu_priv);
91
92 return 0;
93}
94
95static int tx_init_ack(struct osmo_iuup_cn *cn, void *pdu_priv)
96{
97 /* Send Initialization Ack PDU back to the sender */
98 struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");
99 OSMO_ASSERT(ack);
100 osmo_iuup_make_init_ack(ack);
101 return cn->cfg.tx_msg(ack, cn->cfg.node_priv, pdu_priv);
102}
103
104static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,
105 struct osmo_iuup_hdr_ctrl *hdr, void *pdu_priv)
106{
107 switch (hdr->procedure) {
108 case OSMO_IUUP_PROC_INITIALIZATION:
109 switch (hdr->ack_nack) {
110 case OSMO_IUUP_ACKNACK_PROCEDURE:
111 return tx_init_ack(cn, pdu_priv);
112
113 default:
114 break;
115 }
116 /* fall thru */
117 default:
118 LOG_IUUP_CN(cn, LOGL_ERROR,
119 "Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
120 hdr->procedure, hdr->ack_nack);
121 return -EINVAL;
122 }
123}
124
125int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu, void *pdu_priv)
126{
127 struct osmo_iuup_hdr_ctrl *is_ctrl;
128 struct osmo_iuup_hdr_data *is_data;
129 int rc;
130
131 rc = osmo_iuup_classify(true, cn->name, pdu, &is_ctrl, &is_data);
132 if (rc)
133 return rc;
134
135 if (is_ctrl)
136 return rx_control(cn, pdu, is_ctrl, pdu_priv);
137 if (is_data)
138 return rx_data(cn, pdu, is_data, pdu_priv);
139 return rc;
140}
141
142static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)
143{
144 uint8_t frame_nr = cn->next_frame_nr;
145 cn->next_frame_nr = (cn->next_frame_nr + 1) % 0x0f;
146 return frame_nr;
147}
148
149int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu, void *pdu_priv)
150{
151 struct rtp_hdr *rtp_was, *rtp;
152 struct osmo_iuup_hdr_data *iuup_hdr;
153
154 /* Splice an IuUP header in between RTP header and payload data */
155 rtp_was = (void*)pdu->data;
156
157 /* copy the RTP header part backwards by the size needed for the IuUP header */
158 rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr));
159 memmove(rtp, rtp_was, sizeof(*rtp));
160 iuup_hdr = (void*)rtp->data;
161
162 *iuup_hdr = (struct osmo_iuup_hdr_data){
163 .pdu_type = OSMO_IUUP_PDU_DATA_WITH_CRC,
164 .frame_nr = next_frame_nr(cn),
165 .frame_good = OSMO_IUUP_FRAME_GOOD,
166 };
167
168 osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);
169
170 return cn->cfg.tx_msg(pdu, cn->cfg.node_priv, pdu_priv);
171}