/* (C) 2008-2012 by Harald Welte * * All Rights Reserved * * Author: Harald Welte * Pablo Neira Ayuso * * SPDX-License-Identifier: AGPL-3.0+ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * pcap writing of the mlapd load * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat */ #define DLT_LINUX_LAPD 177 #define LINUX_SLL_HOST 0 #define LINUX_SLL_OUTGOING 4 struct pcap_hdr { uint32_t magic_number; uint16_t version_major; uint16_t version_minor; int32_t thiszone; uint32_t sigfigs; uint32_t snaplen; uint32_t network; } __attribute__((packed)); struct pcap_rechdr { uint32_t ts_sec; uint32_t ts_usec; uint32_t incl_len; uint32_t orig_len; } __attribute__((packed)); struct pcap_lapdhdr { uint16_t pkttype; uint16_t hatype; uint16_t halen; uint8_t addr[8]; int16_t protocol; } __attribute__((packed)); osmo_static_assert(offsetof(struct pcap_lapdhdr, hatype) == 2, hatype_offset); osmo_static_assert(offsetof(struct pcap_lapdhdr, halen) == 4, halen_offset); osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset); osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset); osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size); int osmo_pcap_lapd_set_fd(int fd) { struct pcap_hdr pcap_header = { .magic_number = 0xa1b2c3d4, .version_major = 2, .version_minor = 4, .thiszone = 0, .sigfigs = 0, .snaplen = 65535, .network = DLT_LINUX_LAPD, }; if (write(fd, &pcap_header, sizeof(pcap_header)) != sizeof(pcap_header)) { LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n", strerror(errno)); close(fd); return -1; } return 0; } int osmo_pcap_lapd_open(char *filename, mode_t mode) { int fd, rc; LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename); fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode); if (fd < 0) { LOGP(DLLAPD, LOGL_ERROR, "failed to open PCAP file: %s\n", strerror(errno)); return -1; } rc = osmo_pcap_lapd_set_fd(fd); if (rc < 0) { close(fd); return rc; } return fd; } /* This currently only works for the D-Channel */ int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg) { struct timeval tv; struct tmp_pkt { struct pcap_rechdr pcap_rechdr; struct pcap_lapdhdr header; char buf[0]; } __attribute__((packed)); const unsigned int total_pkt_len = sizeof(struct tmp_pkt) + msg->len; struct tmp_pkt *s = alloca(total_pkt_len); /* PCAP file has not been opened, skip. */ if (fd < 0) return 0; memset(s, 0, total_pkt_len); s->pcap_rechdr.ts_sec = 0; s->pcap_rechdr.ts_usec = 0; s->pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr); s->pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr); if (direction == OSMO_LAPD_PCAP_OUTPUT) s->header.pkttype = htons(LINUX_SLL_OUTGOING); else s->header.pkttype = htons(LINUX_SLL_HOST); s->header.hatype = 0; s->header.halen = 0; s->header.addr[0] = 0x01; /* we are the network side */ s->header.protocol = ntohs(48); gettimeofday(&tv, NULL); s->pcap_rechdr.ts_sec = tv.tv_sec; s->pcap_rechdr.ts_usec = tv.tv_usec; memcpy(s->buf, msg->data, msg->len); if (write(fd, s, total_pkt_len) != total_pkt_len) { LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n", strerror(errno)); return -1; } return total_pkt_len; } int osmo_pcap_lapd_close(int fd) { LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n"); return close(fd); }