blob: c488d65a97ac755c254f17e3094b69d4090e46a5 [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>
32
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <limits.h>
37#include <string.h>
38#include <unistd.h>
39
40static void _osmo_client_connect(void *_data)
41{
42 osmo_client_connect((struct osmo_pcap_client *) _data);
43}
44
45static void lost_connection(struct osmo_pcap_client *client)
46{
47 if (client->wqueue.bfd.fd >= 0) {
48 osmo_fd_unregister(&client->wqueue.bfd);
49 close(client->wqueue.bfd.fd);
50 client->wqueue.bfd.fd = -1;
51 }
52
53
54 client->timer.cb = _osmo_client_connect;
55 client->timer.data = client;
56 osmo_timer_schedule(&client->timer, 2, 0);
57}
58
59static void write_data(struct osmo_pcap_client *client, struct msgb *msg)
60{
61 if (osmo_wqueue_enqueue(&client->wqueue, msg) != 0) {
62 LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue.\n");
63 msgb_free(msg);
64 return;
65 }
66}
67
68static int read_cb(struct osmo_fd *fd)
69{
70 char buf[4096];
71 int rc;
72
73 rc = read(fd->fd, buf, sizeof(buf));
74 if (rc <= 0) {
75 struct osmo_pcap_client *client = fd->data;
76 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read.\n");
77 lost_connection(client);
78 return -1;
79 }
80
81 return 0;
82}
83
84static int write_cb(struct osmo_fd *fd, struct msgb *msg)
85{
86 int rc;
87
88 rc = write(fd->fd, msg->data, msg->len);
89 if (rc < 0) {
90 struct osmo_pcap_client *client = fd->data;
91 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write.\n");
92 lost_connection(client);
93 return -1;
94 }
95
96 return 0;
97}
98
99void osmo_client_send_data(struct osmo_pcap_client *client,
100 struct pcap_pkthdr *in_hdr, const uint8_t *data)
101{
102 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100103 struct osmo_pcap_pkthdr *hdr;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200104 struct msgb *msg;
105
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100106 if (in_hdr->caplen > 9000) {
107 LOGP(DCLIENT, LOGL_ERROR,
108 "Capture len too big %zu\n", in_hdr->caplen);
109 return;
110 }
111
112 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "data-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200113 if (!msg) {
114 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate.\n");
115 return;
116 }
117
118 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
119 om_hdr->type = PKT_LINK_DATA;
120
121 msg->l2h = msgb_put(msg, sizeof(*hdr));
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100122 hdr = (struct osmo_pcap_pkthdr *) msg->l2h;
123 hdr->ts_sec = in_hdr->ts.tv_sec;
124 hdr->ts_usec = in_hdr->ts.tv_usec;
125 hdr->caplen = in_hdr->caplen;
126 hdr->len = in_hdr->len;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200127
128 msg->l3h = msgb_put(msg, in_hdr->caplen);
129 memcpy(msg->l3h, data, in_hdr->caplen);
130
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200131 om_hdr->len = htons(msgb_l2len(msg));
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200132
133 write_data(client, msg);
134}
135
136void osmo_client_send_link(struct osmo_pcap_client *client)
137{
138 struct pcap_file_header *hdr;
139 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100140 struct msgb *msg;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200141
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100142 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "link-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200143 if (!msg) {
144 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
145 return;
146 }
147
148
149 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
150 om_hdr->type = PKT_LINK_HDR;
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200151 om_hdr->len = htons(sizeof(*hdr));
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200152
153 hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
154 hdr->magic = 0xa1b2c3d4;
155 hdr->version_major = 2;
156 hdr->version_minor = 4;
157 hdr->thiszone = 0;
158 hdr->sigfigs = 0;
159 hdr->snaplen = UINT_MAX;
160 hdr->linktype = pcap_datalink(client->handle);
161
162 write_data(client, msg);
163}
164
165void osmo_client_connect(struct osmo_pcap_client *client)
166{
167 int fd;
168
169 client->wqueue.read_cb = read_cb;
170 client->wqueue.write_cb = write_cb;
171 client->wqueue.bfd.when = BSC_FD_READ;
172 client->wqueue.bfd.data = client;
173 osmo_wqueue_clear(&client->wqueue);
174
175 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Daniel Willmannb0003682011-07-17 17:48:19 +0200176 client->srv_ip, client->srv_port, OSMO_SOCK_F_CONNECT);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200177 if (fd < 0) {
178 LOGP(DCLIENT, LOGL_ERROR,
179 "Failed to connect to %s:%d\n",
180 client->srv_ip, client->srv_port);
181 lost_connection(client);
182 return;
183 }
184
185 client->wqueue.bfd.fd = fd;
186 if (osmo_fd_register(&client->wqueue.bfd) != 0) {
187 LOGP(DCLIENT, LOGL_ERROR,
188 "Failed to register to BFD.\n");
189 lost_connection(client);
190 return;
191 }
192
193 osmo_client_send_link(client);
194}