blob: ac9d7cd7f0ca0c5cae02b505f8b649c7941ef5cd [file] [log] [blame]
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +02001/*
2 * osmo-pcap-client code
3 *
4 * (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2011 by On-Waves
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <osmo-pcap/osmo_pcap_client.h>
24#include <osmo-pcap/common.h>
25#include <osmo-pcap/wireformat.h>
26
27#include <osmocom/core/msgb.h>
28#include <osmocom/core/select.h>
29#include <osmocom/core/socket.h>
30
31#include <arpa/inet.h>
Holger Hans Peter Freytherddc698f2016-04-24 11:09:13 +020032#include <netinet/in.h>
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +020033
34#include <sys/types.h>
35#include <sys/socket.h>
36
37#include <limits.h>
38#include <string.h>
39#include <unistd.h>
40
41static void _osmo_client_connect(void *_data)
42{
43 osmo_client_connect((struct osmo_pcap_client *) _data);
44}
45
46static void lost_connection(struct osmo_pcap_client *client)
47{
48 if (client->wqueue.bfd.fd >= 0) {
49 osmo_fd_unregister(&client->wqueue.bfd);
50 close(client->wqueue.bfd.fd);
51 client->wqueue.bfd.fd = -1;
52 }
53
54
55 client->timer.cb = _osmo_client_connect;
56 client->timer.data = client;
57 osmo_timer_schedule(&client->timer, 2, 0);
58}
59
60static void write_data(struct osmo_pcap_client *client, struct msgb *msg)
61{
62 if (osmo_wqueue_enqueue(&client->wqueue, msg) != 0) {
63 LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue.\n");
64 msgb_free(msg);
65 return;
66 }
67}
68
69static int read_cb(struct osmo_fd *fd)
70{
71 char buf[4096];
72 int rc;
73
74 rc = read(fd->fd, buf, sizeof(buf));
75 if (rc <= 0) {
76 struct osmo_pcap_client *client = fd->data;
77 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read.\n");
78 lost_connection(client);
79 return -1;
80 }
81
82 return 0;
83}
84
85static int write_cb(struct osmo_fd *fd, struct msgb *msg)
86{
87 int rc;
88
89 rc = write(fd->fd, msg->data, msg->len);
90 if (rc < 0) {
91 struct osmo_pcap_client *client = fd->data;
92 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write.\n");
93 lost_connection(client);
94 return -1;
95 }
96
97 return 0;
98}
99
100void osmo_client_send_data(struct osmo_pcap_client *client,
101 struct pcap_pkthdr *in_hdr, const uint8_t *data)
102{
103 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100104 struct osmo_pcap_pkthdr *hdr;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200105 struct msgb *msg;
106
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100107 if (in_hdr->caplen > 9000) {
108 LOGP(DCLIENT, LOGL_ERROR,
109 "Capture len too big %zu\n", in_hdr->caplen);
110 return;
111 }
112
113 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "data-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200114 if (!msg) {
115 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate.\n");
116 return;
117 }
118
119 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
120 om_hdr->type = PKT_LINK_DATA;
121
122 msg->l2h = msgb_put(msg, sizeof(*hdr));
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100123 hdr = (struct osmo_pcap_pkthdr *) msg->l2h;
124 hdr->ts_sec = in_hdr->ts.tv_sec;
125 hdr->ts_usec = in_hdr->ts.tv_usec;
126 hdr->caplen = in_hdr->caplen;
127 hdr->len = in_hdr->len;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200128
129 msg->l3h = msgb_put(msg, in_hdr->caplen);
130 memcpy(msg->l3h, data, in_hdr->caplen);
131
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200132 om_hdr->len = htons(msgb_l2len(msg));
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200133
134 write_data(client, msg);
135}
136
137void osmo_client_send_link(struct osmo_pcap_client *client)
138{
139 struct pcap_file_header *hdr;
140 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100141 struct msgb *msg;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200142
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100143 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "link-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200144 if (!msg) {
145 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
146 return;
147 }
148
149
150 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
151 om_hdr->type = PKT_LINK_HDR;
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200152 om_hdr->len = htons(sizeof(*hdr));
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200153
154 hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
155 hdr->magic = 0xa1b2c3d4;
156 hdr->version_major = 2;
157 hdr->version_minor = 4;
158 hdr->thiszone = 0;
159 hdr->sigfigs = 0;
160 hdr->snaplen = UINT_MAX;
161 hdr->linktype = pcap_datalink(client->handle);
162
163 write_data(client, msg);
164}
165
166void osmo_client_connect(struct osmo_pcap_client *client)
167{
168 int fd;
169
170 client->wqueue.read_cb = read_cb;
171 client->wqueue.write_cb = write_cb;
172 client->wqueue.bfd.when = BSC_FD_READ;
173 client->wqueue.bfd.data = client;
174 osmo_wqueue_clear(&client->wqueue);
175
176 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Daniel Willmannb0003682011-07-17 17:48:19 +0200177 client->srv_ip, client->srv_port, OSMO_SOCK_F_CONNECT);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200178 if (fd < 0) {
179 LOGP(DCLIENT, LOGL_ERROR,
180 "Failed to connect to %s:%d\n",
181 client->srv_ip, client->srv_port);
182 lost_connection(client);
183 return;
184 }
185
186 client->wqueue.bfd.fd = fd;
187 if (osmo_fd_register(&client->wqueue.bfd) != 0) {
188 LOGP(DCLIENT, LOGL_ERROR,
189 "Failed to register to BFD.\n");
190 lost_connection(client);
191 return;
192 }
193
194 osmo_client_send_link(client);
195}