blob: 73746944d44053452fe9a28fb58eee7629dbec2b [file] [log] [blame]
Pablo Neira Ayuso95306002012-08-22 16:43:59 +02001/* (C) 2008-2012 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * Author: Harald Welte <laforge@gnumonks.org>
6 * Pablo Neira Ayuso <pablo@gnumonks.org>
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 <stdio.h>
24#include <stdint.h>
25#include <stddef.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <sys/time.h>
31#include <arpa/inet.h>
32#include <string.h>
33#include <errno.h>
34
35#include <osmocom/core/msgb.h>
36#include <osmocom/core/logging.h>
37#include <osmocom/core/utils.h>
38
39#include <osmocom/abis/lapd_pcap.h>
40
41/*
42 * pcap writing of the mlapd load
43 * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
44 */
45#define DLT_LINUX_LAPD 177
Harald Welteb4698ef2016-07-04 09:55:26 +020046#define LINUX_SLL_HOST 0
47#define LINUX_SLL_OUTGOING 4
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020048
49struct pcap_hdr {
50 uint32_t magic_number;
51 uint16_t version_major;
52 uint16_t version_minor;
53 int32_t thiszone;
54 uint32_t sigfigs;
55 uint32_t snaplen;
56 uint32_t network;
57} __attribute__((packed));
58
59struct pcap_rechdr {
60 uint32_t ts_sec;
61 uint32_t ts_usec;
62 uint32_t incl_len;
63 uint32_t orig_len;
64} __attribute__((packed));
65
66struct pcap_lapdhdr {
67 uint16_t pkttype;
68 uint16_t hatype;
69 uint16_t halen;
Harald Welteb4698ef2016-07-04 09:55:26 +020070 uint8_t addr[8];
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020071 int16_t protocol;
72} __attribute__((packed));
73
74osmo_static_assert(offsetof(struct pcap_lapdhdr, hatype) == 2, hatype_offset);
75osmo_static_assert(offsetof(struct pcap_lapdhdr, halen) == 4, halen_offset);
76osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset);
77osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset);
78osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size);
79
Harald Welte47bee5b2016-07-04 09:53:44 +020080int osmo_pcap_lapd_set_fd(int fd)
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020081{
Harald Welte47bee5b2016-07-04 09:53:44 +020082 struct pcap_hdr pcap_header = {
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020083 .magic_number = 0xa1b2c3d4,
84 .version_major = 2,
85 .version_minor = 4,
86 .thiszone = 0,
87 .sigfigs = 0,
88 .snaplen = 65535,
89 .network = DLT_LINUX_LAPD,
90 };
91
Harald Welte47bee5b2016-07-04 09:53:44 +020092 if (write(fd, &pcap_header, sizeof(pcap_header))
93 != sizeof(pcap_header)) {
94 LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n",
95 strerror(errno));
96 close(fd);
97 return -1;
98 }
99
100 return 0;
101}
102
103int osmo_pcap_lapd_open(char *filename, mode_t mode)
104{
105 int fd, rc;
106
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200107 LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename);
108
109 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
110 if (fd < 0) {
111 LOGP(DLLAPD, LOGL_ERROR, "failed to open PCAP file: %s\n",
112 strerror(errno));
113 return -1;
114 }
Harald Welte47bee5b2016-07-04 09:53:44 +0200115
116 rc = osmo_pcap_lapd_set_fd(fd);
117 if (rc < 0) {
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200118 close(fd);
Harald Welte47bee5b2016-07-04 09:53:44 +0200119 return rc;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200120 }
Harald Welte47bee5b2016-07-04 09:53:44 +0200121
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200122 return fd;
123}
124
125/* This currently only works for the D-Channel */
126int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg)
127{
128 int numbytes = 0;
129 struct timeval tv;
130 struct pcap_rechdr pcap_rechdr;
131 struct pcap_lapdhdr header;
132 char buf[sizeof(struct pcap_rechdr) +
133 sizeof(struct pcap_lapdhdr) + msg->len];
134
135 /* PCAP file has not been opened, skip. */
136 if (fd < 0)
137 return 0;
138
139 pcap_rechdr.ts_sec = 0;
140 pcap_rechdr.ts_usec = 0;
141 pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr);
142 pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr);
143
Harald Welteb4698ef2016-07-04 09:55:26 +0200144 if (direction == OSMO_LAPD_PCAP_OUTPUT)
145 header.pkttype = htons(LINUX_SLL_OUTGOING);
146 else
147 header.pkttype = htons(LINUX_SLL_HOST);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200148 header.hatype = 0;
149 header.halen = 0;
Harald Welteb4698ef2016-07-04 09:55:26 +0200150 header.addr[0] = 0x01; /* we are the network side */
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200151 header.protocol = ntohs(48);
152
153 gettimeofday(&tv, NULL);
154 pcap_rechdr.ts_sec = tv.tv_sec;
155 pcap_rechdr.ts_usec = tv.tv_usec;
156
157 memcpy(buf + numbytes, &pcap_rechdr, sizeof(pcap_rechdr));
158 numbytes += sizeof(pcap_rechdr);
159
160 memcpy(buf + numbytes, &header, sizeof(header));
161 numbytes += sizeof(header);
162
163 memcpy(buf + numbytes, msg->data, msg->len);
164 numbytes += msg->len;
165
166 if (write(fd, buf, numbytes) != numbytes) {
167 LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n",
168 strerror(errno));
169 return -1;
170 }
171 return numbytes;
172}
173
174int osmo_pcap_lapd_close(int fd)
175{
176 LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n");
177 return close(fd);
178}