/* (C) 2008-2012 by Harald Welte * * All Rights Reserved * * Author: Harald Welte * Pablo Neira Ayuso * * 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 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; uint64_t addr; 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_open(char *filename, mode_t mode) { 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, }; 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; } 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 fd; } /* This currently only works for the D-Channel */ int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg) { int numbytes = 0; struct timeval tv; struct pcap_rechdr pcap_rechdr; struct pcap_lapdhdr header; char buf[sizeof(struct pcap_rechdr) + sizeof(struct pcap_lapdhdr) + msg->len]; /* PCAP file has not been opened, skip. */ if (fd < 0) return 0; pcap_rechdr.ts_sec = 0; pcap_rechdr.ts_usec = 0; pcap_rechdr.incl_len = msg->len + sizeof(struct pcap_lapdhdr); pcap_rechdr.orig_len = msg->len + sizeof(struct pcap_lapdhdr); header.pkttype = 4; header.hatype = 0; header.halen = 0; header.addr = direction == OSMO_LAPD_PCAP_OUTPUT ? 0x0 : 0x1; header.protocol = ntohs(48); gettimeofday(&tv, NULL); pcap_rechdr.ts_sec = tv.tv_sec; pcap_rechdr.ts_usec = tv.tv_usec; memcpy(buf + numbytes, &pcap_rechdr, sizeof(pcap_rechdr)); numbytes += sizeof(pcap_rechdr); memcpy(buf + numbytes, &header, sizeof(header)); numbytes += sizeof(header); memcpy(buf + numbytes, msg->data, msg->len); numbytes += msg->len; if (write(fd, buf, numbytes) != numbytes) { LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n", strerror(errno)); return -1; } return numbytes; } int osmo_pcap_lapd_close(int fd) { LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n"); return close(fd); }