blob: 77d4971e85ce38c243157b920e11abe18356991b [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 *
Harald Welte323d39d2017-11-13 01:09:21 +09008 * SPDX-License-Identifier: AGPL-3.0+
9 *
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020010 * 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 <stdio.h>
26#include <stdint.h>
27#include <stddef.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <sys/time.h>
33#include <arpa/inet.h>
34#include <string.h>
35#include <errno.h>
36
37#include <osmocom/core/msgb.h>
38#include <osmocom/core/logging.h>
39#include <osmocom/core/utils.h>
40
41#include <osmocom/abis/lapd_pcap.h>
42
43/*
44 * pcap writing of the mlapd load
45 * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
46 */
47#define DLT_LINUX_LAPD 177
Harald Welteb4698ef2016-07-04 09:55:26 +020048#define LINUX_SLL_HOST 0
49#define LINUX_SLL_OUTGOING 4
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020050
51struct pcap_hdr {
52 uint32_t magic_number;
53 uint16_t version_major;
54 uint16_t version_minor;
55 int32_t thiszone;
56 uint32_t sigfigs;
57 uint32_t snaplen;
58 uint32_t network;
59} __attribute__((packed));
60
61struct pcap_rechdr {
62 uint32_t ts_sec;
63 uint32_t ts_usec;
64 uint32_t incl_len;
65 uint32_t orig_len;
66} __attribute__((packed));
67
68struct pcap_lapdhdr {
69 uint16_t pkttype;
70 uint16_t hatype;
71 uint16_t halen;
Harald Welteb4698ef2016-07-04 09:55:26 +020072 uint8_t addr[8];
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020073 int16_t protocol;
74} __attribute__((packed));
75
76osmo_static_assert(offsetof(struct pcap_lapdhdr, hatype) == 2, hatype_offset);
77osmo_static_assert(offsetof(struct pcap_lapdhdr, halen) == 4, halen_offset);
78osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset);
79osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset);
80osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size);
81
Harald Welte47bee5b2016-07-04 09:53:44 +020082int osmo_pcap_lapd_set_fd(int fd)
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020083{
Harald Welte47bee5b2016-07-04 09:53:44 +020084 struct pcap_hdr pcap_header = {
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020085 .magic_number = 0xa1b2c3d4,
86 .version_major = 2,
87 .version_minor = 4,
88 .thiszone = 0,
89 .sigfigs = 0,
90 .snaplen = 65535,
91 .network = DLT_LINUX_LAPD,
92 };
93
Harald Welte47bee5b2016-07-04 09:53:44 +020094 if (write(fd, &pcap_header, sizeof(pcap_header))
95 != sizeof(pcap_header)) {
96 LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n",
97 strerror(errno));
98 close(fd);
99 return -1;
100 }
101
102 return 0;
103}
104
105int osmo_pcap_lapd_open(char *filename, mode_t mode)
106{
107 int fd, rc;
108
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200109 LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename);
110
111 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
112 if (fd < 0) {
113 LOGP(DLLAPD, LOGL_ERROR, "failed to open PCAP file: %s\n",
114 strerror(errno));
115 return -1;
116 }
Harald Welte47bee5b2016-07-04 09:53:44 +0200117
118 rc = osmo_pcap_lapd_set_fd(fd);
119 if (rc < 0) {
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200120 close(fd);
Harald Welte47bee5b2016-07-04 09:53:44 +0200121 return rc;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200122 }
Harald Welte47bee5b2016-07-04 09:53:44 +0200123
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200124 return fd;
125}
126
127/* This currently only works for the D-Channel */
128int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg)
129{
130 int numbytes = 0;
131 struct timeval tv;
132 struct pcap_rechdr pcap_rechdr;
133 struct pcap_lapdhdr header;
134 char buf[sizeof(struct pcap_rechdr) +
135 sizeof(struct pcap_lapdhdr) + msg->len];
136
137 /* PCAP file has not been opened, skip. */
138 if (fd < 0)
139 return 0;
140
141 pcap_rechdr.ts_sec = 0;
142 pcap_rechdr.ts_usec = 0;
143 pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr);
144 pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr);
145
Harald Welteb4698ef2016-07-04 09:55:26 +0200146 if (direction == OSMO_LAPD_PCAP_OUTPUT)
147 header.pkttype = htons(LINUX_SLL_OUTGOING);
148 else
149 header.pkttype = htons(LINUX_SLL_HOST);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200150 header.hatype = 0;
151 header.halen = 0;
Harald Welteb4698ef2016-07-04 09:55:26 +0200152 header.addr[0] = 0x01; /* we are the network side */
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200153 header.protocol = ntohs(48);
154
155 gettimeofday(&tv, NULL);
156 pcap_rechdr.ts_sec = tv.tv_sec;
157 pcap_rechdr.ts_usec = tv.tv_usec;
158
159 memcpy(buf + numbytes, &pcap_rechdr, sizeof(pcap_rechdr));
160 numbytes += sizeof(pcap_rechdr);
161
162 memcpy(buf + numbytes, &header, sizeof(header));
163 numbytes += sizeof(header);
164
165 memcpy(buf + numbytes, msg->data, msg->len);
166 numbytes += msg->len;
167
168 if (write(fd, buf, numbytes) != numbytes) {
169 LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n",
170 strerror(errno));
171 return -1;
172 }
173 return numbytes;
174}
175
176int osmo_pcap_lapd_close(int fd)
177{
178 LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n");
179 return close(fd);
180}