blob: c83bc60c3837286c5cf379f5e09b279814228665 [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
46
47struct pcap_hdr {
48 uint32_t magic_number;
49 uint16_t version_major;
50 uint16_t version_minor;
51 int32_t thiszone;
52 uint32_t sigfigs;
53 uint32_t snaplen;
54 uint32_t network;
55} __attribute__((packed));
56
57struct pcap_rechdr {
58 uint32_t ts_sec;
59 uint32_t ts_usec;
60 uint32_t incl_len;
61 uint32_t orig_len;
62} __attribute__((packed));
63
64struct pcap_lapdhdr {
65 uint16_t pkttype;
66 uint16_t hatype;
67 uint16_t halen;
68 uint64_t addr;
69 int16_t protocol;
70} __attribute__((packed));
71
72osmo_static_assert(offsetof(struct pcap_lapdhdr, hatype) == 2, hatype_offset);
73osmo_static_assert(offsetof(struct pcap_lapdhdr, halen) == 4, halen_offset);
74osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset);
75osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset);
76osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size);
77
78int osmo_pcap_lapd_open(char *filename, mode_t mode)
79{
80 int fd;
81 struct pcap_hdr pcap_header = {
82 .magic_number = 0xa1b2c3d4,
83 .version_major = 2,
84 .version_minor = 4,
85 .thiszone = 0,
86 .sigfigs = 0,
87 .snaplen = 65535,
88 .network = DLT_LINUX_LAPD,
89 };
90
91 LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename);
92
93 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
94 if (fd < 0) {
95 LOGP(DLLAPD, LOGL_ERROR, "failed to open PCAP file: %s\n",
96 strerror(errno));
97 return -1;
98 }
99 if (write(fd, &pcap_header, sizeof(pcap_header))
100 != sizeof(pcap_header)) {
101 LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n",
102 strerror(errno));
103 close(fd);
104 return -1;
105 }
106 return fd;
107}
108
109/* This currently only works for the D-Channel */
110int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg)
111{
112 int numbytes = 0;
113 struct timeval tv;
114 struct pcap_rechdr pcap_rechdr;
115 struct pcap_lapdhdr header;
116 char buf[sizeof(struct pcap_rechdr) +
117 sizeof(struct pcap_lapdhdr) + msg->len];
118
119 /* PCAP file has not been opened, skip. */
120 if (fd < 0)
121 return 0;
122
123 pcap_rechdr.ts_sec = 0;
124 pcap_rechdr.ts_usec = 0;
125 pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr);
126 pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr);
127
128 header.pkttype = 4;
129 header.hatype = 0;
130 header.halen = 0;
131 header.addr = direction == OSMO_LAPD_PCAP_OUTPUT ? 0x0 : 0x1;
132 header.protocol = ntohs(48);
133
134 gettimeofday(&tv, NULL);
135 pcap_rechdr.ts_sec = tv.tv_sec;
136 pcap_rechdr.ts_usec = tv.tv_usec;
137
138 memcpy(buf + numbytes, &pcap_rechdr, sizeof(pcap_rechdr));
139 numbytes += sizeof(pcap_rechdr);
140
141 memcpy(buf + numbytes, &header, sizeof(header));
142 numbytes += sizeof(header);
143
144 memcpy(buf + numbytes, msg->data, msg->len);
145 numbytes += msg->len;
146
147 if (write(fd, buf, numbytes) != numbytes) {
148 LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n",
149 strerror(errno));
150 return -1;
151 }
152 return numbytes;
153}
154
155int osmo_pcap_lapd_close(int fd)
156{
157 LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n");
158 return close(fd);
159}