blob: 01296dc290d3558e297b9e038fd8693f458dd830 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* Implementation of the C7 UDP link */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010 by On-Waves
5 * All Rights Reserved
6 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21
22#include <bsc_data.h>
23#include <udp_input.h>
24#include <mtp_data.h>
25#include <mtp_pcap.h>
26#include <snmp_mtp.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080027#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080028
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080029#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080030
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34
35#include <string.h>
36#include <unistd.h>
37
38static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg)
39{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010040 struct mtp_udp_link *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080041 int rc;
42
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010043 link = fd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080044
45 LOGP(DINP, LOGL_DEBUG, "Sending MSU: %s\n", hexdump(msg->data, msg->len));
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010046 if (link->base.pcap_fd >= 0)
47 mtp_pcap_write_msu(link->base.pcap_fd, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080048
49 /* the assumption is we have connected the socket to the remote */
50 rc = sendto(fd->fd, msg->data, msg->len, 0,
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010051 (struct sockaddr *) &link->remote, sizeof(link->remote));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080052 if (rc != msg->len) {
53 LOGP(DINP, LOGL_ERROR, "Failed to write msg to socket: %d\n", rc);
54 return -1;
55 }
56
57 return 0;
58}
59
60static int udp_read_cb(struct bsc_fd *fd)
61{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010062 struct mtp_link *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080063 struct udp_data_hdr *hdr;
64 struct msgb *msg;
65 int rc;
66 unsigned int length;
67
68 msg = msgb_alloc_headroom(4096, 128, "UDP datagram");
69 if (!msg) {
70 LOGP(DINP, LOGL_ERROR, "Failed to allocate memory.\n");
71 return -1;
72 }
73
74
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +010075 link = (struct mtp_link *) fd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080076 rc = read(fd->fd, msg->data, 2096);
77 if (rc < sizeof(*hdr)) {
78 LOGP(DINP, LOGL_ERROR, "Failed to read at least size of the header: %d\n", rc);
79 rc = -1;
80 goto exit;
81 }
82
83 /* throw away data as the link is down */
84 if (link->the_link->available == 0) {
85 LOGP(DINP, LOGL_ERROR, "The link is down. Not forwarding.\n");
86 rc = 0;
87 goto exit;
88 }
89
90 hdr = (struct udp_data_hdr *) msgb_put(msg, sizeof(*hdr));
91
92 if (hdr->data_type == UDP_DATA_RETR_COMPL || hdr->data_type == UDP_DATA_RETR_IMPOS) {
93 LOGP(DINP, LOGL_ERROR, "Link retrieval done. Restarting the link.\n");
Holger Hans Peter Freytherc8405692011-01-02 20:24:08 +010094 mtp_link_down(link);
95 mtp_link_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080096 goto exit;
97 } else if (hdr->data_type > UDP_DATA_MSU_PRIO_3) {
98 LOGP(DINP, LOGL_ERROR, "Link failure. retrieved message.\n");
Holger Hans Peter Freytherc8405692011-01-02 20:24:08 +010099 mtp_link_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800100 goto exit;
101 }
102
103 length = ntohl(hdr->data_length);
104 if (length + sizeof(*hdr) > (unsigned int) rc) {
105 LOGP(DINP, LOGL_ERROR, "The MSU payload does not fit: %u + %u > %d \n",
106 length, sizeof(*hdr), rc);
107 rc = -1;
108 goto exit;
109 }
110
111 msg->l2h = msgb_put(msg, length);
112
113 LOGP(DINP, LOGL_DEBUG, "MSU data on: %p data %s.\n", link, hexdump(msg->data, msg->len));
114 if (link->pcap_fd >= 0)
115 mtp_pcap_write_msu(link->pcap_fd, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100116 mtp_link_set_data(link, msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800117
118exit:
119 msgb_free(msg);
120 return rc;
121}
122
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100123static int udp_link_dummy(struct mtp_link *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800124{
125 /* nothing todo */
126 return 0;
127}
128
129static void do_start(void *_data)
130{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100131 struct mtp_udp_link *link = (struct mtp_udp_link *) _data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800132
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100133 snmp_mtp_activate(link->session, link->link_index);
134 mtp_link_up(&link->base);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800135}
136
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100137static int udp_link_reset(struct mtp_link *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800138{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100139 struct mtp_udp_link *ulnk;
140
141 ulnk = (struct mtp_udp_link *) link;
142
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800143 LOGP(DINP, LOGL_NOTICE, "Will restart SLTM transmission in %d seconds.\n",
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100144 ulnk->reset_timeout);
145
146 snmp_mtp_deactivate(ulnk->session, ulnk->link_index);
Holger Hans Peter Freytherc8405692011-01-02 20:24:08 +0100147 mtp_link_down(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800148
149 /* restart the link in 90 seconds... to force a timeout on the BSC */
150 link->link_activate.cb = do_start;
151 link->link_activate.data = link;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100152 bsc_schedule_timer(&link->link_activate, ulnk->reset_timeout, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800153 return 0;
154}
155
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100156static int udp_link_write(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800157{
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100158 struct mtp_udp_link *ulnk;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800159 struct udp_data_hdr *hdr;
160
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100161 ulnk = (struct mtp_udp_link *) link;
162
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800163 hdr = (struct udp_data_hdr *) msgb_push(msg, sizeof(*hdr));
164 hdr->format_type = UDP_FORMAT_SIMPLE_UDP;
165 hdr->data_type = UDP_DATA_MSU_PRIO_0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100166 hdr->data_link_index = htons(ulnk->link_index);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800167 hdr->user_context = 0;
168 hdr->data_length = htonl(msgb_l2len(msg));
169
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100170 if (write_queue_enqueue(&ulnk->write_queue, msg) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800171 LOGP(DINP, LOGL_ERROR, "Failed to enqueue msg.\n");
172 msgb_free(msg);
173 return -1;
174 }
175
176 return 0;
177}
178
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100179static int udp_link_start(struct mtp_link *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800180{
181 LOGP(DINP, LOGL_NOTICE, "UDP input is ready.\n");
182 do_start(link);
183 return 0;
184}
185
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100186int link_udp_init(struct mtp_udp_link *link, int src_port, const char *remote, int remote_port)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800187{
188 struct sockaddr_in addr;
189 int fd;
190 int on;
191
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100192 write_queue_init(&link->write_queue, 100);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800193
194 /* function table */
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100195 link->base.shutdown = udp_link_dummy;
196 link->base.clear_queue = udp_link_dummy;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800197
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100198 link->base.reset = udp_link_reset;
199 link->base.start = udp_link_start;
200 link->base.write = udp_link_write;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800201
202 /* socket creation */
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100203 link->write_queue.bfd.data = link;
204 link->write_queue.bfd.when = BSC_FD_READ;
205 link->write_queue.read_cb = udp_read_cb;
206 link->write_queue.write_cb = udp_write_cb;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800207
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100208 link->write_queue.bfd.fd = fd = socket(AF_INET, SOCK_DGRAM, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800209 if (fd < 0) {
210 LOGP(DINP, LOGL_ERROR, "Failed to create UDP socket.\n");
211 return -1;
212 }
213
214 on = 1;
215 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
216
217 memset(&addr, 0, sizeof(addr));
218 addr.sin_family = AF_INET;
219 addr.sin_port = htons(src_port);
220 addr.sin_addr.s_addr = INADDR_ANY;
221
222 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
223 perror("Failed to bind UDP socket");
224 close(fd);
225 return -1;
226 }
227
228 /* now connect the socket to the remote */
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100229 memset(&link->remote, 0, sizeof(link->remote));
230 link->remote.sin_family = AF_INET;
231 link->remote.sin_port = htons(remote_port);
232 inet_aton(remote, &link->remote.sin_addr);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800233
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100234 if (bsc_register_fd(&link->write_queue.bfd) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800235 LOGP(DINP, LOGL_ERROR, "Failed to register BFD.\n");
236 close(fd);
237 return -1;
238 }
239
240 return 0;
241}